5 CADENAS

Las secciones siguientes describen el tipo de datos string, que es un alias para la clase String.

 

En esta sección

 

Utilizar cadenas (Guía de programación de C#)

Cómo: Analizar cadenas con el método Split (Guía de programación de C#)

Cómo: Buscar cadenas mediante los métodos String (Guía de programación de C#)

Cómo: Buscar cadenas mediante expresiones regulares (Guía de programación de C#)

Cómo: Unir varias cadenas (Guía de programación de C#)

Cómo: Modificar el contenido de cadenas (Guía de programación de C#)

 

 

 

 

 

Una cadena de C# es una matriz de caracteres que se declara utilizando la palabra clave string. Un literal de cadena se declara utilizando las comillas, como se muestra en el siguiente ejemplo:

 

string s = “Hello, World!”;

 

Puede extraer subcadenas y concatenar cadenas de la siguiente manera:

 

string s1 = “orange”;

string s2 = “red”;

 

s1 += s2;

System.Console.WriteLine(s1); // outputs “orangered”

 

s1 = s1.Substring(2, 5);

System.Console.WriteLine(s1); // outputs “anger”

 

Los objetos de cadena son inmutables, lo que significa que no se pueden cambiar una vez creados. Los métodos que actúan sobre las cadenas, devuelven los nuevos objetos de cadena. En el ejemplo anterior, cuando el contenido de s1 y s2 se concatenan para formar una sola cadena, las dos cadenas que contienen “orange” y “red” no se modifican. El operador += crea una nueva cadena que contiene el contenido combinado. Como resultado, s1 ahora hace referencia a una cadena totalmente diferente. Todavía existe una cadena que sólo contiene “orange” , pero deja de hacerse referencia a ella cuando se concatena s1.

 

Por consiguiente, y por razones de rendimiento, si se realizan grandes cantidades de concatenaciones u otras manipulaciones de cadenas, se debería utilizar la clase StringBuilder, de la siguiente manera:

 

System.Text.StringBuilder sb = new System.Text.StringBuilder();

sb.Append(“one “);

sb.Append(“two “);

sb.Append(“three”);

string str = sb.ToString(); 

 

La clase StringBuilder se describe con mayor detalle en la sección “Utilizar Stringbuilder”.

 

Trabajar con cadenas

Carácter de escape

Los caracteres de escape como “\n” y (nueva línea) y “\t” (tabulador) se pueden incluir en cadenas. La línea:

 

string hello = “Hello\nWorld!”; 

 

 

equivale a:

 

Hello

World!

 

Si desea incluir una barra diagonal inversa, ésta debe estar precedida de otra barra diagonal inversa. La cadena siguiente:

 

string filePath = “\\\\My Documents\\”; 

 

equivale a:

 

\\My Documents\

 

El símbolo @

 

El símbolo @ indica al constructor de cadena que debe omitir caracteres de escape y saltos de línea. Las dos cadenas siguientes son, por consiguiente, idénticas:

 

string p1 = “\\\\My Documents\\My Files\\”;

string p2 = @”\\My Documents\My Files\”; 

 

 

ToString()

Al igual que todos los objetos derivados de Object, las cadenas proporcionan el método ToString, que convierte un valor en una cadena. Este método se puede utilizar para convertir valores numéricos en cadenas de la siguiente manera:

 

int year = 1999;

string msg = “Eve was born in ” + year.ToString();

System.Console.WriteLine(msg); // outputs “Eve was born in 1999” 

 

Tener acceso a los caracteres individuales

 

Se obtiene acceso a los caracteres individuales contenidos en una cadena utilizando métodos como SubString(), Replace(),, Split() y Trim().

 

string s3 = “Visual C# Express”;

                

System.Console.WriteLine(s3.Substring(7, 2)); // outputs “C#”

System.Console.WriteLine(s3.Replace(“C#”, “Basic”)); // outputs “Visual Basic Express” 

También es posible copiar los caracteres en una matriz de caracteres, tal como se muestra a continuación:

 

string s4 = “Hello, World”;

char[] arr = s4.ToCharArray(0, s4.Length);

 

foreach (char c in arr)

{

System.Console.Write(c); // outputs “Hello, World”

} 

 

Puede obtener acceso a los caracteres individuales de una cadena con un índice:

 

string s5 = “Printing backwards”;

 

for (int i = 0; i < s5.Length; i++)

{

System.Console.Write(s5[s5.Length – i – 1]); // outputs “sdrawkcab gnitnirP”

} 

 

Cambiar mayúsculas y minúsculas

 

Para cambiar las letras en una cadena a mayúsculas o minúsculas, se utiliza ToUpper() o ToLower(), de la siguiente forma:

 

string s6 = “Battle of Hastings, 1066”;

 

System.Console.WriteLine(s6.ToUpper()); // outputs “BATTLE OF HASTINGS 1066”

System.Console.WriteLine(s6.ToLower()); // outputs “battle of hastings 1066”

 

Comparaciones

 

La manera más simple de comparar dos cadenas es utilizar los operadores == y !=, que realizan una comparación con distinción entre mayúsculas y minúsculas.

 

string color1 = “red”;

string color2 = “green”;

string color3 = “red”;

 

if (color1 == color3)

{

System.Console.WriteLine(“Equal”);

}

if (color1 != color2)

{

System.Console.WriteLine(“Not equal”);

} 

Los objetos String también tienen un método CompareTo() que devuelve un valor entero, basado en si una cadena es menor que (<) o mayor que (>) otra. Al comparar las cadenas, se utiliza el valor Unicode, y las minúsculas tienen un valor menor que las mayúsculas.

 

string s7 = “ABC”;

string s8 = “abc”;

 

if (s7.CompareTo(s8) > 0)

{

System.Console.WriteLine(“Greater-than”);

}

else

{

System.Console.WriteLine(“Less-than”);

} 

 

Para buscar una cadena dentro de otra, utilice IndexOf(). IndexOf() devuelve -1 si la cadena de búsqueda no se encuentra; en caso contrario devuelve el índice de la primera posición de la cadena, con base cero.

 

string s9 = “Battle of Hastings, 1066”;

 

System.Console.WriteLine(s9.IndexOf(“Hastings”)); // outputs 10

System.Console.WriteLine(s9.IndexOf(“1967”)); // outputs -1 

 

Dividir una cadena en subcadenas

 

Dividir una cadena en subcadenas (al igual que dividir una frase en palabras) es una tarea común de programación. El método Split() toma una matriz de char de delimitadores (por ejemplo, un carácter de espacio) y devuelve una matriz de subcadenas. Para obtener acceso a esta matriz con foreach:

 

char[] delimit = new char[] { ‘ ‘ };

string s10 = “The cat sat on the mat.”;

foreach (string substr in s10.Split(delimit))

{

System.Console.WriteLine(substr);

} 

 

Este código genera cada palabra en una línea separada de la siguiente forma:

 

The

cat

sat

on

the

mat.

 

Utilizar StringBuilder

 

La clase StringBuilder crea un búfer de cadena que proporciona el mejor rendimiento si el programa realiza una gran manipulación de cadenas. La cadena StringBuilder también permite reasignar los caracteres individuales, algo que el tipo de datos de cadena integrado no admite. Por ejemplo, este código cambia el contenido de una cadena sin crear una nueva cadena:

 

System.Text.StringBuilder sb = new System.Text.StringBuilder(“Rat: the ideal pet”);

sb[0] = ‘C’;

System.Console.WriteLine(sb.ToString());

System.Console.ReadLine(); 

 

En este ejemplo, se utiliza un objeto StringBuilder para crear una cadena a partir de un conjunto de tipos numéricos:

 

class TestStringBuilder

{

static void Main()

{

System.Text.StringBuilder sb = new System.Text.StringBuilder();

 

// Create a string composed of numbers 0 – 9

for (int i = 0; i < 10; i++)

{

sb.Append(i.ToString());

}

System.Console.WriteLine(sb); // displays 0123456789

 

// Copy one character of the string (not possible with a System.String)

sb[0] = sb[9];

 

System.Console.WriteLine(sb); // displays 9123456789

}

} 

 

 

 

 

 

5.2.- ANALIZAR CADENAS CON EL MÉTODO SPLIT

 

El ejemplo de código siguiente muestra cómo analizar una cadena con el método System.String.Split. Este método devuelve una matriz de cadenas en la que cada elemento es una palabra. Como entrada, Split toma una matriz de caracteres que indican los caracteres que se utilizan como delimitadores. En este ejemplo, se utilizan espacios, comas, dos puntos, puntos y comas y tabuladores. Se pasa una matriz que contiene estos delimitadores a Split, y cada palabra de la frase se muestra por separado utilizando la matriz de cadenas resultante.

 

Ejemplo

class TestStringSplit

{

static void Main()

{

char[] delimiterChars = { ‘ ‘, ‘,’, ‘.’, ‘:’, ‘\t’ };

 

string text = “one\ttwo three:four,five six seven”;

System.Console.WriteLine(“Original text: ‘{0}'”, text);

 

string[] words = text.Split(delimiterChars);

System.Console.WriteLine(“{0} words in text:”, words.Length);

 

foreach (string s in words)

{

System.Console.WriteLine(s);

}

}

} 

 

Resultados

Original text: ‘one two three:four,five six seven’

7 words in text:

one

two

three

four

five

six

seven 

 

 

 

 

 

 

5.3.- BUSCAR CADENAS MEDIANTE LOS MÉTODOS STRING

 

El tipo string, que es un alias de la clase System.String, proporciona varios métodos útiles para buscar el contenido de una cadena. El ejemplo siguiente utiliza los métodos IndexOf, LastIndexOf, StartsWith y EndsWith.

 

Ejemplo

class StringSearch

{

static void Main()

{

string str = “A silly sentence used for silly purposes.”;

System.Console.WriteLine(“‘{0}'”,str);

 

bool test1 = str.StartsWith(“a silly”);

System.Console.WriteLine(“starts with ‘a silly’? {0}”, test1);

 

bool test2 = str.StartsWith(“a silly”, System.StringComparison.OrdinalIgnoreCase);

System.Console.WriteLine(“starts with ‘a silly’? {0} (ignoring case)”, test2);

 

bool test3 = str.EndsWith(“.”);

System.Console.WriteLine(“ends with ‘.’? {0}”, test3);

 

int first = str.IndexOf(“silly”);

int last = str.LastIndexOf(“silly”);

string str2 = str.Substring(first, last – first);

System.Console.WriteLine(“between two ‘silly’ words: ‘{0}'”, str2);

}

} 

 

Resultados

‘A silly sentence used for silly purposes.’

starts with ‘a silly’? False

starts with ‘a silly’? True (ignore case)

ends with ‘.’? True

between two ‘silly’ words: ‘silly sentence used for ‘

 

 

 

 

5.4.- BUSCAR CADENAS MEDIANTE EXPRESIONES REGULARES

 

La clase System.Text.RegularExpressions.Regex se puede utilizar para buscar cadenas. Estas búsquedas pueden tener distinta complejidad, desde ser muy sencillas hasta hacer un gran uso de expresiones regulares. A continuación se ofrecen dos ejemplos de búsqueda de cadenas con la clase Regex. Para obtener más información, vea Expresiones regulares de .NET Framework.

 

Ejemplo

El código siguiente es una aplicación de consola que realiza una búsqueda simple de cadenas sin distinción entre mayúsculas y minúsculas en una matriz. El método estático System.Text.RegularExpressions.Regex.IsMatch(System.String,System.String,System.Text.RegularExpressions.RegexOptions) realiza la búsqueda a partir de la cadena de búsqueda y de la cadena que contiene el patrón de búsqueda. En este caso, se utiliza un tercer argumento para indicar que no se debe distinguir entre mayúsculas y minúsculas. Para obtener más información, vea System.Text.RegularExpressions.RegexOptions.

 

class TestRegularExpressions

{

static void Main()

{

string[] sentences =

{

“cow over the moon”,

“Betsy the Cow”,

“cowering in the corner”,

“no match here”

};

 

string sPattern = “cow”;

 

foreach (string s in sentences)

{

System.Console.Write(“{0,24}”, s);

 

if (System.Text.RegularExpressions.Regex.IsMatch(s, sPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase))

{

System.Console.WriteLine(” (match for ‘{0}’ found)”, sPattern);

}

else

{

System.Console.WriteLine();

}

}

}

} 

 

Resultados

cow over the moon (match for ‘cow’ found)

Betsy the Cow (match for ‘cow’ found)

cowering in the corner (match for ‘cow’ found)

no match here 

 

El código siguiente es una aplicación de consola que utiliza expresiones regulares para validar el formato de cada cadena de una matriz. La validación requiere que cada cadena tenga la forma de un número de teléfono en el que tres grupos de dígitos se separan por guiones. Los dos primeros grupos contienen tres dígitos, y el tercero, cuatro. Esto se logra con la expresión regular ^\\d{3}-\\d{3}-\\d{4}$. Para obtener más información, vea Elementos del lenguaje de expresiones regulares.

 

class TestRegularExpressionValidation

{

static void Main()

{

string[] numbers =     

{

“123-456-7890”,

“444-234-22450”,

“690-203-6578”,

“146-893-232”,

“146-839-2322”,

“4007-295-1111”,

“407-295-1111”,

“407-2-5555”,

};

 

string sPattern = “^\\d{3}-\\d{3}-\\d{4}$”;

 

foreach (string s in numbers)

{

System.Console.Write(“{0,14}”, s);

 

if (System.Text.RegularExpressions.Regex.IsMatch(s, sPattern))

{

System.Console.WriteLine(” – valid”);

}

else

{

System.Console.WriteLine(” – invalid”);

}

}

}

} 

 

Resultados

123-456-7890 – valid

444-234-22450 – invalid

690-203-6578 – valid

146-893-232 – invalid

146-839-2322 – valid

4007-295-1111 – invalid

407-295-1111 – valid

407-2-5555 – invalid 

 

 

 

 

5.5.- UNIR VARIAS CADENAS

 

Hay dos maneras de unir varias cadenas: con el operador + que la clase String sobrecarga y con la clase StringBuilder. El operador + es fácil de usar y hace el código más intuitivo, pero trabaja en serie; se crea una nueva cadena para cada uso del operador, de modo que cambiar varios operadores a la vez es ineficiente. Por ejemplo:

 

string two = “two”;

string str = “one ” + two + ” three”;

System.Console.WriteLine(str); 

 

Aunque aparecen cuatro cadenas en el código (las tres cadenas que se combinan y la cadena final que contiene las otras tres), se crean cinco cadenas en total porque las dos primeras se combinan primero y crean una cadena que contiene “one two”. La tercera se anexa separadamente para formar la cadena final almacenada en str.

Alternativamente, la clase StringBuilder se puede utilizar para agregar cada cadena a un objeto que, a continuación, crea la cadena final en un paso. Esta estrategia se muestra en el ejemplo siguiente.

 

Ejemplo

En el código siguiente se utiliza el método Append de la clase StringBuilder para combinar tres cadenas sin el efecto de encadenamiento del operador +.

 

class StringBuilderTest

{

static void Main()

{

string two = “two”;

 

System.Text.StringBuilder sb = new System.Text.StringBuilder();

sb.Append(“one “);

sb.Append(two);

sb.Append(” three”);

System.Console.WriteLine(sb.ToString());

 

string str = sb.ToString();

System.Console.WriteLine(str);

}

} 

 

 

 

 

 

5.6.- MODIFICAR EL CONTENIDO DE CADENAS

 

Las cadenas son inmutables, por lo que no es posible modificar su contenido. Sin embargo, el contenido de una cadena se puede extraer a un formulario no inmutable y modificarse para formar a continuación una nueva instancia de la cadena.

 

Ejemplo

En el ejemplo siguiente se utiliza el método ToCharArray para extraer el contenido de una cadena a una matriz de tipo char. A continuación, se modifican algunos de los elementos de esa matriz. Después se utiliza la matriz char para crear una nueva instancia de la cadena.

 

class ModifyStrings

{

static void Main()

{

string str = “The quick brown fox jumped over the fence”;

System.Console.WriteLine(str);

 

char[] chars = str.ToCharArray();

int animalIndex = str.IndexOf(“fox”);

if (animalIndex != -1)

{

chars[animalIndex++] = ‘c’;

chars[animalIndex++] = ‘a’;

chars[animalIndex] = ‘t’;

}

 

string str2 = new string(chars);

System.Console.WriteLine(str2);

}

} 

 

Resultados

The quick brown fox jumped over the fence

The quick brown cat jumped over the fence 

4 MATRICES

Una matriz es una estructura de datos que contiene una serie de variables del mismo tipo. Las matrices se declaran con un tipo:

type[] arrayName;

 

Los ejemplos siguientes crean matrices unidimensionales, multidimensionales y escalonadas:

 

class TestArraysClass

{                    

static void Main()

{

// Declare a single-dimensional array

int[] array1 = new int[5];

 

// Declare and set array element values

int[] array2 = new int[] { 1, 3, 5, 7, 9 };

 

// Alternative syntax

int[] array3 = { 1, 2, 3, 4, 5, 6 };

 

// Declare a two dimensional array

int[,] multiDimensionalArray1 = new int[2, 3];

 

// Declare and set array element values

int[,] multiDimensionalArray2 = { { 1, 2, 3 }, { 4, 5, 6 } };

 

// Declare a jagged array

int[][] jaggedArray = new int[6][];

 

// Set the values of the first array in the jagged array structure

jaggedArray[0] = new int[4] { 1, 2, 3, 4 };

}

} 

 

Información general sobre las matrices

 

Una matriz tiene las propiedades siguientes:

 

  • Una matriz puede ser unidimensional, multidimensional o escalonada.
  • El valor predeterminado de los elementos numéricos de matriz se establece en cero y el de los elementos de referencia se establece en null.
  • Una matriz escalonada es una matriz de matrices y por consiguiente sus elementos son tipos de referencia y se inicializan en null.
  • Las matrices se indizan basadas en cero: una matriz con n elementos se indiza desde 0 hasta n-1.
  • Los elementos de una matriz pueden ser de cualquier tipo, incluido el tipo matriz.
  • Los tipos de matriz son tipos de referencia derivados del tipo base abstracto Array. Puesto que este tipo implementa IEnumerable e IEnumerable, puede utilizar la iteración foreach en todas las matrices de C#.

 

 

  • Utilizar matrices como objetos (Guía de programación de C#)
  • Utilizar foreach son matrices (Guía de programación de C#)
  • Pasar matrices como parámetros (Guía de programación de C#)
  • Pasar matrices mediante Ref y Out (Guía de programación de C#)
  • Ejemplo Arrays

4.1.- UTILIZAR MATRICES COMO OBJETOS

 

En C#, las matrices son de hecho objetos, y no simplemente regiones direccionables de memoria contigua como ocurre en C y C++. Array es el tipo base abstracto de todos los tipos de matriz. Las propiedades y otros miembros de la clase Array se pueden utilizar cuando sea necesario. Un ejemplo de esto sería utilizar la propiedad Lengthpara obtener la longitud de una matriz. El siguiente código asigna la longitud de la matriz numbers, que es 5, a una variable denominada lengthOfNumbers:

 

int[] numbers = { 1, 2, 3, 4, 5 };

int lengthOfNumbers = numbers.Length; 

 

La clase System.Array proporciona muchos otros métodos y propiedades útiles para ordenar, buscar y copiar matrices.

 

Ejemplo

En este ejemplo se utiliza la propiedad Rank para mostrar el número de dimensiones de una matriz.

 

class TestArraysClass

{

static void Main()

{

// Declare and initialize an array:

int[,] theArray = new int[5, 10];

System.Console.WriteLine(“The array has {0} dimensions.”, theArray.Rank);

}

} 

 

Resultado

The array has 2 dimensions.

 

 

4.2.- UTILIZAR FOREACH

 

C# dispone de la instrucción foreach. Esta instrucción proporciona un modo simple y limpio de recorrer en iteración los elementos de una matriz. Por ejemplo, el siguiente código crea una matriz denominada numbers y la recorre mediante la instrucción foreach:

 

int[] numbers = { 4, 5, 6, 1, 2, 3, -2, -1, 0 };

foreach (int i in numbers)

{

System.Console.WriteLine(i);

} 

 

Con matrices multidimensionales, se puede utilizar el mismo método para recorrer los elementos, por ejemplo:

 

int[,] numbers2D = new int[3, 2] { { 9, 99 }, { 3, 33 }, { 5, 55 } };

foreach (int i in numbers2D)

{

System.Console.Write(“{0} “, i);

} 

 

El resultado de este ejemplo es:

9 99 3 33 5 55

 

Sin embargo, con matrices multidimensionales, utilizar un bucle for anidado proporciona más control sobre los elementos de la matriz.

4.3.- PASAR MATRICES COMO PARÁMETROS

 

Las matrices se pueden pasar a los métodos como parámetros. Cuando las matrices son tipos de referencia, el método puede cambiar el valor de los elementos.

 

Pasar matrices unidimensionales como parámetros

Una matriz unidimensional inicializada se puede pasar a un método. Por ejemplo:

 

PrintArray(theArray); 

 

El método llamado en la línea anterior se podría definir como:

 

void PrintArray(int[] arr)

{

// method code

} 

 

Asimismo, es posible inicializar y pasar una matriz en una sola operación. Por ejemplo:

 

PrintArray(new int[] { 1, 3, 5, 7, 9 }); 

 

Ejemplo 1

En el siguiente ejemplo, una matriz de cadena se inicializa y se pasa como parámetro al método PrintArray, el cual muestra los elementos de la matriz:

 

class ArrayClass

{

static void PrintArray(string[] arr)

{

for (int i = 0; i < arr.Length; i++)

{

System.Console.Write(arr[i] + “{0}”, i < arr.Length – 1 ? ” ” : “”);

}

System.Console.WriteLine();

}

 

static void Main()

{

// Declare and initialize an array:

string[] weekDays = new string[] { “Sun”, “Mon”, “Tue”, “Wed”, “Thu”, “Fri”, “Sat” };

 

// Pass the array as a parameter:

PrintArray(weekDays);

}

} 

 

 

Resultado 1

Sun Mon Tue Wed Thu Fri Sat

 

Pasar matrices multidimensionales como parámetros

Una matriz multidimensional inicializada se puede pasar a un método. Por ejemplo, si theArray es una matriz bidimensional:

 

PrintArray(theArray);

 

El método llamado en la línea anterior se podría definir como:

 

void PrintArray(int[,] arr)

{

// method code

} 

 

Asimismo, es posible inicializar y pasar una matriz en una sola operación. Por ejemplo:

 

PrintArray(new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } });

 

 

Ejemplo 2

En el siguiente ejemplo, una matriz bidimensional de cadena se inicializa y se pasa como parámetro al método PrintArray, el cual muestra los elementos de la matriz:

 

class ArrayClass2D

{

static void PrintArray(int[,] arr)

{

// Display the array elements:

for (int i = 0; i < 4; i++)

{

for (int j = 0; j < 2; j++)

{

System.Console.WriteLine(“Element({0},{1})={2}”, i, j, arr[i, j]);

}

}

}

static void Main()

{

// Pass the array as a parameter:

PrintArray(new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } });

}

} 

 

 

Element(0,0)=1

Element(0,1)=2

Element(1,0)=3

Element(1,1)=4

Element(2,0)=5

Element(2,1)=6

Element(3,0)=7

Element(3,1)=8

4.4.- PASAR MATRICES MEDIANTE REF Y OUT

 

Al igual que todos los parámetros out, un parámetro out de tipo de matriz debe asignarse antes de utilizarlo; es decir, debe asignarlo el destinatario. Por ejemplo:

 

static void TestMethod1(out int[] arr)

{

arr = new int[10]; // definite assignment of arr

} 

 

Al igual que todos los parámetros ref, un parámetro ref de tipo de matriz debe asignarlo el llamador. Por consiguiente, no es necesario que lo asigne el destinatario. Un parámetro ref de un tipo de matriz puede cambiar como resultado de la llamada. Por ejemplo, a la matriz se le puede asignar el valor null o se puede inicializar con otra matriz. Por ejemplo:

 

static void TestMethod2(ref int[] arr)

{

arr = new int[10]; // arr initialized to a different array

} 

 

Los dos ejemplos siguientes muestran la diferencia entre out y ref cuando se utilizan para pasar matrices a métodos.

 

Ejemplo 1

En este ejemplo, la matriz theArray se declara en el llamador (el método Main) y se inicializa en el método FillArray. A continuación, los elementos de la matriz se devuelven al método que realizó la llamada y se muestran.

 

class TestOut

{

static void FillArray(out int[] arr)

{

// Initialize the array:

arr = new int[5] { 1, 2, 3, 4, 5 };

}

 

static void Main()

{

int[] theArray; // Initialization is not required

 

// Pass the array to the callee using out:

FillArray(out theArray);

 

// Display the array elements:

System.Console.WriteLine(“Array elements are:”);

for (int i = 0; i < theArray.Length; i++)

{

System.Console.Write(theArray[i] + ” “);

}

}

} 

 

Resultado 1

Array elements are:

1 2 3 4 5

 

Ejemplo 2

En este ejemplo, la matriz theArray se inicializa en el llamador (el método Main) y se pasa al método FillArray mediante el parámetro ref. Algunos de los elementos de la matriz se actualizan en el método FillArray. A continuación, los elementos de la matriz se devuelven al método que realizó la llamada y se muestran.

 

class TestRef

{

static void FillArray(ref int[] arr)

{

// Create the array on demand:

if (arr == null)

{

arr = new int[10];

}

// Fill the array:

arr[0] = 1111;

arr[4] = 5555;

}

 

static void Main()

{

// Initialize the array:

int[] theArray = { 1, 2, 3, 4, 5 };

 

// Pass the array using ref:

FillArray(ref theArray);

 

// Display the updated array:

System.Console.WriteLine(“Array elements are:”);

for (int i = 0; i < theArray.Length; i++)

{

System.Console.Write(theArray[i] + ” “);

}

}

} 

 

Resultado 2

Array elements are:

1111 2 3 4 5555

 

 

 

3 TIPOS DE DATOS

C# es un lenguaje con establecimiento inflexible de tipos; por lo tanto, cada variable y objeto debe tener un tipo declarado.

Información general sobre los tipos de datos

Un tipo de datos se puede describir como:

  • Un tipo de datos integrado, como int o char, o bien
  • Un tipo de datos definidos por el usuario, como class o interface.
  • Los tipos de datos también se pueden definir como:
  • Tipos de valores (Referencia de C#), que almacenan los valores, o bien
  • Tipos de referencia (Referencia de C#), que almacenan referencias a los datos reales.

Secciones relacionadas

Para obtener más información:

  • Conversión (Guía de programación de C#)
  • Conversión boxing y unboxing (Guía de programación de C#)
  • Tipos (Referencia de C#)
  • Objetos, clases y estructuras (Guía de programación de C#)

3.1.- TIPOS DE VALORES

Los tipos de valor consisten en dos categorías principales:

  • Estructuras
  • Enumeraciones

Las estructuras se dividen en las siguientes categorías:

  • Tipos numéricos
    • Tipos integrales
    • Tipos de punto flotante
    • decimal
  • Estructuras definidas por el usuario.

Características principales de los tipos de valor

Variable que está basada directamente en tipos de valor que contienen valores. La asignación de una variable de tipo de valor a otra copia el valor contenido. Esto es diferente de la asignación de variables de tipo de referencia, que copia una referencia en el objeto pero no el propio objeto.

Todos los tipos de valor se derivan implícitamente de la clase System.ValueType.

A diferencia de los tipos de referencia, no es posible obtener un nuevo tipo de un tipo de valor. No obstante, al igual que los tipos de referencia, las estructuras pueden implementar interfaces.

A diferencia de los tipos de referencia, los tipos de valor no pueden incluir el valor null. Sin embargo, la característica tipos que aceptan valores NULL permite asignar null a tipos de valores.

Cada tipo de valor tiene un constructor implícito predeterminado que inicializa el valor predeterminado de ese tipo. Para obtener información sobre los valores predeterminados de los tipos de valor, vea Tabla de valores predeterminados.

Características principales de los tipos simples

Todos los tipos simples (aquellos que forman parte integral del lenguaje C#) son alias de los tipos del sistema .NET Framework. Por ejemplo, int es un alias de System.Int32. Para una lista completa de alias, vea Tabla de tipos integrados (Referencia de C#).

Las expresiones constantes, cuyos operandos son todos constantes de tipos simples, se evalúan en tiempo de compilación.

Los tipos simples se pueden inicializar mediante literales. Por ejemplo, ‘A’ es un literal del tipo char y 2001 es un literal del tipo int.

Inicializar tipos de valor

Las variables locales de C# se deben inicializar antes de utilizarlas. Por consiguiente, si se declara una variable local sin inicialización como ésta:

int myInt;        

no se podrá utilizar hasta que se inicialice. La inicialización se puede realizar mediante la siguiente instrucción:

myInt = new int(); // Invoke default constructor for int type.

que equivale a:

myInt = 0; // Assign an initial value, 0 in this example.

También se puede realizar la declaración y la inicialización en la misma instrucción:

int myInt = new int();

O bien

int myInt = 0;

Con el operador new, se realiza una llamada al constructor predeterminado del tipo específico y se asigna el valor predeterminado a la variable. En el ejemplo anterior, el constructor predeterminado asigna a myInt el valor 0. Para obtener más información sobre valores asignados mediante constructores predeterminados, vea Tabla de valores predeterminados.

Con los tipos definidos por el usuario, se utiliza new para invocar el constructor predeterminado. Por ejemplo, la siguiente instrucción invoca el constructor predeterminado de la estructura Point:

Point p = new Point(); // Invoke default constructor for the struct.

Después de esta llamada, la estructura se considera definitivamente asignada; es decir, todos sus miembros se inicializan con sus valores predeterminados.

Para obtener más información acerca del operador new.

3.1.1.- ESTRUCTURAS

Un tipo struct es un tipo de valor que se suele utilizar para encapsular pequeños grupos de variables relacionadas, como las coordenadas de un rectángulo o las características de un elemento de un inventario. En el ejemplo siguiente se muestra una declaración de estructura sencilla.

 

public struct Book

{

public decimal price;

public string title;

public string author;

}

 

Comentarios

Las estructuras también pueden contener constructores, constantes, campos, métodos, propiedades, indizadores, operadores, eventos y tipos anidados, aunque si se requieren estos miembros, se debe considerar la posibilidad de crear una clase en vez de un tipo.

Las estructuras pueden implementar una interfaz, pero no pueden heredar de otra estructura. Por esa razón, los miembros de estructura no se pueden declarar como protected.

3.1.2.- ENUMERACIONES

La palabra clave enum se utiliza para declarar una enumeración, un tipo distinto que consiste en un conjunto de constantes con nombre denominado lista de enumeradores. Cada tipo de enumeración tiene un tipo subyacente, que puede ser cualquier tipo integral excepto char. El tipo predeterminado subyacente de los elementos de la enumeración es int. De forma predeterminada, el primer enumerador tiene el valor 0 y el valor de cada enumerador sucesivo se incrementa en 1. Por ejemplo:


enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri};

En esta enumeración, Sat es 0, Sun es 1, Mon es 2 y así sucesivamente. Los enumeradores pueden tener inicializadores que reemplazan a los valores predeterminados. Por ejemplo:


enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};

En esta enumeración, se obliga a que la secuencia de elementos empiece en 1 en vez de en 0.

A una variable de tipo Days se le puede asignar cualquier valor en el intervalo del tipo subyacente; los valores no se limitan a las constantes con nombre.

El valor predeterminado de un enum E es el valor producido por la expresión (E)0.

Nota

Un enumerador no puede contener espacio en blanco en su nombre.

El tipo subyacente especifica el almacenamiento asignado para cada enumerador. No obstante, se necesita una conversión explícita para convertir un tipo enum a un tipo integral. Por ejemplo, la siguiente instrucción asigna el enumerador Sun a una variable de tipo int utilizando una conversión explícita para convertir de enum a int:

int x = (int)Days.Sun;

Cuando se aplica System.FlagsAttribute a una enumeración que contiene algunos elementos combinados con una operación OR bit a bit, se observará que el atributo afecta el comportamiento de enum cuando se utiliza con algunas herramientas. Se pueden observar estos cambios al utilizar herramientas tales como los métodos de la clase Console, el Evaluador de expresiones, etc. (Vea el ejemplo 3).

Programación sólida

Asignar valores adicionales a nuevas versiones de enumeraciones o cambiar los valores de los miembros de enumeración en una nueva versión, puede producir problemas para el código fuente dependiente. Es común que los valores enum se utilicen en instrucciones switch y, si se han agregado elementos adicionales al tipo enum, la comprobación de los valores predeterminados puede devolver true de forma inesperada.

Si otros desarrolladores van a utilizar su código, es importante proporcionar instrucciones sobre cómo su código debe reaccionar si se agregan nuevos elementos a cualquier tipo enum.

Ejemplo

En este ejemplo, se declara la enumeración Days. Dos enumeradores se convierten explícitamente en un número entero y se asignan a variables de número entero.

// keyword_enum.cs

// enum initialization:

using System;

public class EnumTest

{

enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};

static void Main()

{


int x = (int)Days.Sun;


int y = (int)Days.Fri;

Console.WriteLine(“Sun = {0}”, x);

Console.WriteLine(“Fri = {0}”, y);

}

}

Resultados

Sun = 2

Fri = 7

En este ejemplo, la opción de tipo base se utiliza para declarar un enum cuyos miembros son del tipo long. Observe que a pesar de que el tipo subyacente de la enumeración es long, los miembros de la enumeración todavía deben convertirse explícitamente al tipo long mediante una conversión de tipos.

// keyword_enum2.cs

// Using long enumerators

using System;

public class EnumTest

{

enum Range :long {Max = 2147483648L, Min = 255L};

static void Main()

{


long x = (long)Range.Max;


long y = (long)Range.Min;

Console.WriteLine(“Max = {0}”, x);

Console.WriteLine(“Min = {0}”, y);

}

}

Resultados

Max = 2147483648

Min = 255

El ejemplo de código siguiente ilustra el uso y efecto del atributo System.FlagsAttribute en una declaración enum.

// enumFlags.cs

// Using the FlagsAttribute on enumerations.

using System;

[Flags]

public enum CarOptions

{

SunRoof = 0x01,

Spoiler = 0x02,

FogLights = 0x04,

TintedWindows = 0x08,

}

class FlagTest

{

static void Main()

{

CarOptions options = CarOptions.SunRoof | CarOptions.FogLights;

Console.WriteLine(options);

Console.WriteLine((int)options);

}

}

Resultados

SunRoof, FogLights

5

Comentarios

Observe que si se quita el inicializador de Sat=1, el resultado será:

Sun = 1

Fri = 6

Comentarios

Observe que si elimina FlagsAttribute, el ejemplo generará lo siguiente:

5

5

3.2.- TIPOS DE REFERENCIA

Las variables de tipos de referencia, conocidas como objetos, almacenan referencias a los datos reales. Esta sección presenta las palabras clave siguientes utilizadas para declarar tipos de referencia:

Esta sección también presenta los siguientes tipos de referencia integrados:

3.3.- CONVERSIONES DE TIPOS DE DATOS

La conversión entre tipos de datos se puede hacer de forma explícita utilizando una conversión de tipos; en algunos casos, se permiten conversiones implícitas. Por ejemplo:

static void TestCasting()

{

int i = 10;

float f = 0;

f = i; // An implicit conversion, no data will be lost.

f = 0.5F;

i = (int) f; // An explicit conversion. Information will be lost.

}

Una conversión de tipos invoca de forma explícita al operador de conversión de un tipo a otro. En la conversión de tipos se producirá un error si no se ha definido ninguno de estos operadores. Puede escribir operadores de conversión personalizados para convertir entre los tipos definidos por el usuario. Para obtener más información sobre la definición de un operador de conversión, vea explicit (Referencia de C#) e implicit (Referencia de C#).

Ejemplo

El siguiente programa convierte explícitamente un tipo double en un tipo int. El programa no se compilará sin el operador de conversión de tipo.

class Test

{

static void Main()

{

double x = 1234.7;

int a;

a = (int)x; // cast double to int

System.Console.WriteLine(a);

}

}

Resultado

1234

3.4.- CONVERSION. BOXING Y UNBOXING

Las conversiones boxing y unboxing permiten tratar los tipos de valor como objetos. La aplicación de la conversión boxing a un tipo de valor empaqueta el tipo en una instancia del tipo de referencia Object. Esto permite almacenar el tipo de valor en el montón del recolector de elementos no utilizados. La conversión unboxing extrae el tipo de valor del objeto. En este ejemplo, se aplica la conversión boxing a la variable de entero i y ésta se asigna al objeto o.

int i = 123;

object o = (object) i; // boxing

A continuación, se puede aplicar la conversión unboxing al objeto o y asignarlo a la variable de entero i:

o = 123;

i = (int) o; // unboxing

Rendimiento

Con relación a las asignaciones simples, las conversiones boxing y unboxing son procesos que consumen muchos recursos. Cuando se aplica la conversión boxing a un tipo de valor, se debe asignar y construir un objeto completamente nuevo. En menor grado, la conversión de tipos requerida para aplicar la conversión unboxing también es costosa.

MAIN() Y ARGUMENTOS

El método Main es el punto de entrada del programa, donde crea objetos e invoca otros métodos. En un programa de C#, sólo puede haber un punto de entrada.

 

 

class TestClass

{

static void Main(string[] args)

{

// Display the number of command line arguments:

System.Console.WriteLine(args.Length);

}

}

 

Información general

  • El método Main es el punto de entrada del programa, donde se inicia y finaliza el control.
  • Se declara dentro de una clase o una estructura. Debe ser estático y no debería ser público. (En el ejemplo anterior, recibe el acceso predeterminado de privado.)
  • Puede tener un tipo de valor devuelto void o int.
  • El método Main se puede declarar con o sin parámetros.
  • Los parámetros se pueden leer como argumentos de la línea de comandos indizados basados en cero.
  • A diferencia de C y C++, el nombre del programa no se trata como el primer argumento de la línea de comandos.

 

En esta sección

  • Argumentos de línea de comandos (Guía de programación de C#)
  • Cómo: Mostrar argumentos de línea de comandos (Guía de programación de C#)
  • Cómo: Obtener acceso a argumentos de línea de comandos mediante Foreach (Guía de programación de C#)
  • Valores devueltos de Main() (Guía de programación de C#)

 

 

 

E LÍNEA DE COMANDOS

 

Se pueden utilizar argumentos en el método Main; si se utilizan, tendrá una de las formas siguientes:

 

static int Main(string[] args)

 

 

static void Main(string[] args)

 

El parámetro del método Main es una matriz de tipo String que representa los argumentos de la línea de comandos. Normalmente se utiliza la propiedad Length para comprobar si existen argumentos; por ejemplo:

 

 

if (args.Length == 0)

{

System.Console.WriteLine(“Please enter a numeric argument.”);

return 1;

}

 

También se pueden convertir los argumentos de tipo string en tipos numéricos mediante la clase Convert el método Parse. Por ejemplo, la instrucción siguiente convierte la cadena en un número long utilizando el método Parse en la clase Int64:

 

long num = Int64.Parse(args[0]);

 

También se puede utilizar el tipo long de C#, que equivale a Int64:

long num = long.Parse(args[0]); 

Igualmente, es posible usar el método ToInt64 de la clase Convert para lograr el mismo objetivo:

long num = Convert.ToInt64(s); 

 

Para obtener más información, vea Parse y Convert.

 

Ejemplo

En este ejemplo, el programa toma un argumento en tiempo de ejecución, lo convierte en un número entero y calcula el factorial del número. Si no se proporciona ningún argumento, el programa emite un mensaje en el que se describe la forma de utilizarlo correctamente.

 

// arguments: 3 

 

 

public class Functions

{

public static long Factorial(int n)

{

if (n < 0) { return -1; } //error result – undefined

if (n > 256) { return -2; } //error result – input is too big

 

if (n == 0) { return 1; }

 

// Calculate the factorial iteratively rather than recursively:

 

long tempResult = 1;

for (int i = 1; i <= n; i++)

{

tempResult *= i;

}

return tempResult;

}

} 

 

 

 

class MainClass

{

static int Main(string[] args)

{

// Test if input arguments were supplied:

if (args.Length == 0)

{

System.Console.WriteLine(“Please enter a numeric argument.”);

System.Console.WriteLine(“Usage: Factorial <num>”);

return 1;

}

 

try

{

// Convert the input arguments to numbers:

int num = int.Parse(args[0]);

 

System.Console.WriteLine(“The Factorial of {0} is {1}.”, num, Functions.Factorial(num));

return 0;

}

catch (System.FormatException)

{

System.Console.WriteLine(“Please enter a numeric argument.”);

System.Console.WriteLine(“Usage: Factorial <num>”);

return 1;

}

}

} 

 

Resultado

The Factorial of 3 is 6.

 

 

Comentarios

A continuación se muestran dos ejecuciones de ejemplo del programa en las que se supone que el nombre del programa es Factorial.exe.

 

Ejecución nº 1:

Escriba la siguiente línea de comandos:

Factorial 10

Obtiene el resultado siguiente:

The Factorial of 10 is 3628800.

 

Ejecución nº 2:

Escriba la siguiente línea de comandos:

Factorial

Obtiene el resultado siguiente:

Please enter a numeric argument.

Usage: Factorial <num>

2.2.- COMO MOSTRAR ARGUMENTOS DE LÍNEA DE COMANDOS

 

Los argumentos proporcionados a una aplicación ejecutable en la línea de comandos son accesibles a través de un parámetro opcional de Main. Los argumentos se proporcionan en forma de matriz de cadenas. Cada elemento de la matriz contiene un argumento. Se quita el espacio en blanco entre los argumentos. Por ejemplo, considere estas invocaciones de la línea de comandos de una aplicación ejecutable ficticia:

 

Entrada en la línea de comandos

Matriz de cadenas pasadas a Main  

executable.exe a b c

“a”

“b”

“c” 

executable.exe one two

“one”

“two” 

executable.exe “one two” three

“one two”

“three” 

 

Ejemplo

Este ejemplo muestra los argumentos de la línea de comandos pasados a una aplicación de línea de comandos. El resultado mostrado es para la primera entrada de la tabla anterior.

 

class CommandLine

{

static void Main(string[] args)

{

// The Length property provides the number of array elements

System.Console.WriteLine(“parameter count = {0}”, args.Length);

 

for (int i = 0; i < args.Length; i++)

{

System.Console.WriteLine(“Arg[{0}] = [{1}]”, i, args[i]);

}

}

} 

 

Resultados

parameter count = 3

Arg[0] = [a]

Arg[1] = [b]

Arg[2] = [c] 

 

 

 

 

 

Otro enfoque para recorrer en iteración la matriz es utilizar la instrucción foreach como se muestra en este ejemplo. La instrucción foreach se puede utilizar para recorrer en iteración una matriz, una clase de colección de .NET Framework o cualquier clase o estructura que implemente la interfaz IEnumerable.

 

Ejemplo

En este ejemplo se muestra cómo imprimir los argumentos de la línea de comandos con foreach.

 

// arguments: John Paul Mary 

 

 

class CommandLine2

{

static void Main(string[] args)

{

System.Console.WriteLine(“Number of command line parameters = {0}”, args.Length);

 

foreach (string s in args)

{

System.Console.WriteLine(s);

}

}

} 

 

Resultados

Number of command line parameters = 3

John

Paul

Mary 

 

 

 

 

    

2.4.- VALORES DEVUELTOS DE MAIN()

 

El método Main puede ser de tipo void:

 

 

static void Main()

{

//…

}

 

También puede devolver un valor de tipo int:

 

 

static int Main()

{

//…

return 0;

}

 

Si no se va a utilizar el valor que devuelve el método Main, entonces devolver void permite crear un código un poco más simple. Sin embargo, devolver un entero permite que el programa relacione información de estado con otros programas o secuencias de comandos que invocan al ejecutable. En el ejemplo siguiente se muestra cómo utilizar el valor que devuelve Main.

 

Ejemplo

En este ejemplo, se utiliza un archivo de proceso por lotes para ejecutar un programa y probar el valor que devuelve la función Main. Cuando un programa se ejecuta en Windows, cualquier valor que devuelva la función Main se almacena en una variable de entorno denominada ERRORLEVEL. Al inspeccionar la variable ERRORLEVEL, los archivos de proceso por lotes pueden determinar en consecuencia el resultado de la ejecución. Tradicionalmente, un valor devuelto de cero indica una ejecución correcta. El programa que se muestra a continuación es un programa muy simple que devuelve un valor de cero desde la función Main.

 

class MainReturnValTest

{

static int Main()

{

//…

return 0;

}

} 

 

Dado que este ejemplo utiliza un archivo de proceso por lotes, es mejor compilar el código desde la línea de comandos, como se muestra en Cómo: Generar desde la línea de comandos.

Luego, se utiliza un archivo de proceso por lotes para invocar al ejecutable que resulta del ejemplo de código anterior. Puesto que el código devuelve un valor de cero, el archivo de proceso por lotes creará un informe de operación correcta, pero si el código anterior se cambia para que devuelva un valor distinto de cero y luego se vuelve a compilar, la ejecución posterior del archivo de proceso por lotes indicará un error.

 

rem test.bat

@echo off

MainReturnValueTest

@if “%ERRORLEVEL%” == “0” goto good

 

:fail

echo Execution Failed

echo return value = %ERRORLEVEL%

goto end

 

:good

echo Execution Succeded

echo return value = %ERRORLEVEL%

goto end

 

:end 

 

Resultados del ejemplo

Execution Succeded

return value = 0

 

 

INTRODUCCIÓN RÁPIDA AL LENGUAJE C#

DENTRO DE UN PROGRAMA C#

Para comprender cómo funciona un programa en C#, analizaremos cada línea de código de C# del típico programa “Hola a todos”.

Hello World, estilo de C#

El lenguaje de C# utiliza las clases para organizar y empaquetar el código. De hecho, todo el código ejecutable de C# debe estar contenido en una clase, incluso en un programa breve como “Hello World!”. A continuación se muestra el programa completo que muestra “Hello World!” en la ventana de la consola.

C#  

using System;

// A “Hello World!” program in C#

namespace HelloWorld

{

class Hello

{

static void Main()

{

System.Console.WriteLine(“Hello World!”);

}

}

} 

Directivas using y espacios de nombres

Cuando se crea una aplicación de consola con Visual C# Express, las primeras líneas en el editor de código contienen directivas using que muestran varios espacios de nombres de .NET Framework. Un espacio de nombres es una manera de agrupar clases y estructuras de una manera que limita su ámbito y evita conflictos de nombres con otras clases y estructuras. Cuando crea un programa en Visual C# Express, se crea automáticamente un espacio de nombres. Para utilizar las clases de otros espacios de nombres en su programa, debe especificarlos con una directivausing. Los espacios de nombres más comúnmente utilizados en .NET Framework se muestran de forma predeterminada cuando crea una nueva aplicación. Si utiliza clases de otros espacios de nombres en la biblioteca de clases, debe agregar una directiva using para ese espacio de nombres al archivo de código fuente. Para obtener más información sobre los espacios de nombres, vea Espacios de nombres (Visual C# Express).

Cuando el Editor de código detecta que se ha declarado una clase o estructura que no puede encontrar en los espacios de nombres enumerados en las directivas using actuales, sugerirá espacios de nombres que contienen la clase o estructura.

Comentarios

Después de las instrucciones using, la línea siguiente contiene un comentario. Los comentarios son útiles para incluir notas personales o destinadas a otros programadores.

C#  

// A “Hello World!” program in C# 

 

Los caracteres // convierten el resto de la línea en un comentario. Un bloque de texto también se puede convertir en comentario si se coloca entre los caracteres /* y */, por ejemplo:

 

C#  

/* A “Hello World!” program in C#.

This program displays the string “Hello World!” on the screen. */

 

También puede utilizar una opción de formato para comentar código automáticamente.

Clases

El lenguaje C# utiliza las clases para empaquetar código: todo código de C# ejecutable debe estar contenido en una clase. Para obtener más información, vea Clases (Visual C# Express).

Main()

  • Cualquier programa en C# debe contener un método Main, en el cual se inicia y se termina la ejecución. Este método es donde se crean objetos y se ejecutan otros métodos. Main es un método static que reside dentro de una clase o una estructura. En el ejemplo de “Hello World!”, se encuentra dentro de la clase Program .

    Los métodos Main pueden definirse de alguna de las siguientes formas:

 

  • Puede devolver void:

 

C#  

static void Main()

{

//…

} 

 

 

  • También puede devolver un valor de tipo int:

 

C#  

static int Main()

{

//…

return 0;

} 

 

 

  • Puede aceptar argumentos, lo cual resulta útil para crear programas de línea de comandos:

 

C#  

static void Main(string[] args)

{

//…

} 

    

 

  • O bien

 

C#  

 

static int Main(string[] args)

{

//…

return 0;

} 

 

El parámetro del método Main es una matriz de tipo string que representa los argumentos de la línea de comandos utilizados para invocar el programa. Observe que, a diferencia de C++, esta matriz no incluye el nombre del archivo ejecutable (.exe). Para obtener más información, vea Main() y argumentos de línea de comandos (Guía de programación de C#).

 

Entrada y salida de consola

Los programas de consola de C# generalmente utilizan los servicios de entrada y salida proporcionados por la clase Console de .NET Framework. La instrucción Console.WriteLine(“Hello, World!”); utiliza el método WriteLine. Muestra su parámetro de cadena en la ventana de línea de comandos seguida de una nueva línea. Otros métodos de Console se utilizan para otras operaciones de entrada y salida. La clase Console es un miembro del espacio de nombres System. Si no se incluyera la instrucción using System; al principio del programa, tendría que especificar las clases de System de la siguiente manera:

 

C#  

System.Console.WriteLine(“Hello World!”);

 

El método WriteLine es muy útil y lo utilizará a menudo si escribe aplicaciones de consola.

 

WriteLine puede mostrar cadenas:

C#  

Console.WriteLine(“Hello World!”); 

 

WriteLine también puede mostrar números:

C#  

int x = 42;

Console.WriteLine(x);

 

Si necesita mostrar varios elementos, utilice {0} para representar el primer elemento, {1} para el segundo elemento, y así sucesivamente, de la forma siguiente.

 

C#  

int year = 1066;

string battle = “Battle of Hastings”;

Console.WriteLine(“The {0} took place in {1}.”, battle, year);

 

El resultado presentará la siguiente apariencia: The Battle of Hastings took place in 1066.

ESTRUCTURA DE UN PROGRAMA C#

 

Cuando crea una aplicación de C#, tiene la opción de crear una aplicación de consola o una aplicación para Windows. Ambas difieren no sólo en el tipo de interfaz de usuario; también pueden diferir en su flujo de ejecución.

 

Aplicaciones para Windows

En una aplicación para Windows típica, con una interfaz de usuario gráfica, casi todas las acciones que tienen lugar después del inicio se realizan en respuesta a acciones del usuario como mover el mouse, seleccionar una opción de menú o escribir texto. Tales acciones producen eventos y llaman a métodos especiales de la aplicación denominados controladores de eventos. Un controlador de eventos inicia casi todo lo que un programa de Windows hace. Cuando no se genera ningún evento, el programa simplemente espera y no hace nada.

Si suele utilizar lenguajes de programación procedimentales, como COBOL, BASIC o FORTRAN, tendrá que acostumbrarse al modelo orientado a eventos. La diferencia más fundamental es que, en la programación orientada a eventos, otro software, incluso el propio sistema operativo, llama a los métodos controladores de eventos en la aplicación. No hay ninguna manera de saber a qué métodos va a llamar. Puede elegir los eventos que controlará en la aplicación, pero no puede saber de antemano el orden exacto en el que se van a producir esos eventos.

En una aplicación para Windows típica, los campos, matrices y colecciones que alojan el estado de la aplicación se colocan en la clase principal Form, que se denomina Form1 de forma predeterminada. En el ámbito de clase, estos miembros son accesibles desde todos los métodos controladores de eventos que se implementan en la misma clase Form. Cuando se llama a un controlador de eventos, éste puede realizar una acción que modifique los datos de la aplicación y, cuando el método devuelve un valor, la aplicación reanuda su estado de espera. Por ejemplo, un formulario puede contener un control TextBox y un botón Actualizar. Cuando el usuario hace clic en el botón, el controlador de eventos de la aplicación podría hacer algo como obtener el texto del control TextBox y, a continuación, agregarlo a una lista de otras cadenas almacenadas en el ámbito de clase. Después de que se ha agregado la cadena, la aplicación regresa al estado de espera. Otros controladores de eventos pueden realizar otros tipos de acciones en esa misma lista de cadenas en respuesta a los datos proporcionados por el usuario.

Sus propias clases personalizadas pueden enviar y recibir eventos utilizando los mismos mecanismos que los formularios Windows Forms.

 

Aplicaciones de consola

En muchas aplicaciones de consola, el flujo de ejecución pasa de una instrucción a la siguiente hasta que se llega al final del programa y la aplicación finaliza. Por supuesto, esto no ocurre siempre porque los eventos del teclado y los eventos del sistema generados por objetos como temporizadores y conexiones de red pueden seguir controlando la aplicación de consola. Las aplicaciones de consola sencillas a menudo constan de una sola clase, la cual contiene el método Main. Sin embargo, las aplicaciones más complejas pueden contener cualquier número de clases.

 

 

ESPACIOS DE NOMBRES

 

Los espacios de nombres son una manera de organizar los distintos tipos que aparecen en un programa en C#. Conceptualmente es similar a una carpeta en un sistema de archivo del equipo. Al igual que las carpetas, los espacios de nombres permiten a las clases tener un nombre completo único. Un programa en C# contiene uno o más espacios de nombres, que quedan definidos por el programador o como parte de una biblioteca de clases previamente escrita.

Por ejemplo, el espacio de nombres System incluye la clase Console, una clase que contiene los métodos para leer y escribir en la ventana de la consola. El espacio de nombres System también contiene múltiples espacios de nombres diferentes, como System.IO y System.Collections. Sólo .NET Framework tiene más de ochenta espacios de nombres, cada uno con miles de clases: los espacios de nombres se utilizan para minimizar la confusión que se podría producir entre tipos y métodos con nombres parecidos.

Si escribe una clase fuera de una declaración de espacio de nombres, el compilador proporcionará un espacio de nombres predeterminado para esa clase.

 

Accesos directos a espacios de nombres

Para utilizar el método WriteLine, definido en la clase Console contenida en el espacio de nombres System, utilice una línea de código como ésta:

 

C#  

System.Console.WriteLine(“Hello, World!”); 

 

Rápidamente se hace muy pesado el no olvidarse de preceder con System todos los métodos contenidos en Console, por lo que insertar la directiva using en el inicio del archivo de código fuente de C#, resulta una forma rápida y útil:

 

C#  

using System; 

 

La inclusión de using System; hace que no sea necesario incluir el espacio de nombres System y, por tanto, puede escribir únicamente lo siguiente:

 

C#  

Console.WriteLine(“Hello, World!”);

 

Crear su propio espacio de nombres

Es común utilizar espacios de nombres cuando se trabaja en programas grandes. Utilizar espacios de nombres propios proporciona un grado de control sobre los métodos y tipos con nombres parecidos. Por ejemplo, suponga que está escribiendo una aplicación que carga datos estadísticos y archivos de imagen de un disco. Podría crear dos nuevos espacios de nombres, uno denominado Images y otro denominado StatisticalData. Si utiliza dos espacios de nombres separados, todos los nombres de los métodos definidos en cada espacio de nombres serán únicos, aun cuando las clases individuales tengan el mismo nombre. Esto significa que podría tener una clase denominada FileHandling en ambos espacios de nombres, y ambos contendrían un método denominado Load. La clase deseada se especificaría haciendo referencia a StatisticalData.FileHandling o Images.FileHandling

Una práctica recomendada es crear una carpeta independiente para cada espacio de nombres en el proyecto de Visual C# Express.

 

Ejemplo

El siguiente ejemplo define dos espacios de nombres, cada uno con una clase denominada FileHandling. Al especificar el espacio de nombres, se hace posible diferenciar rápidamente entre las clases y los métodos que contienen.

 

CLASES

 

C# es un lenguaje de programación orientado a objetos y, como otros lenguajes modernos, agrupa campos relacionados, métodos, propiedades y eventos en estructuras de datos denominadas clases.

 

Clases y objetos

Una clase es básicamente un plano para un tipo de datos personalizado. Cuando se define una clase, se utiliza cargándola en la memoria. Una clase que se ha cargado en la memoria se denomina objeto o instancia. Crea una instancia de una clase utilizando la palabra clave de C# new.

El siguiente es un ejemplo de definición de una clase denominada SampleClass y de creación de un objeto denominado sampleClass1 que es una instancia de esa clase. Como C# requiere que la función Main esté definida en una clase, el código siguiente también define una clase Program, pero esa clase no se utiliza para crear un objeto.

 

C#  

using System;

 

class SampleClass

{

public void SayHello()

{

Console.WriteLine(“Hello, World!”);

}

}

 

class Program

{

//Main is the entrypoint, where every C# program starts

static void Main(string[] args)

{

SampleClass sampleClass1 = new SampleClass(); // Create an object

sampleClass1.SayHello(); // Call a method

}

} 

 

Al igual que se puede construir cualquier número de casas con un mismo plano, se pueden crear instancias de cualquier número de objetos con la misma clase. Es muy común tener matrices o listas que contienen muchos objetos de la misma clase. Cada instancia de la clase ocupa su propio espacio de memoria y los valores de sus campos (excepto los campos estáticos, como se describe a continuación) son independientes. En el ejemplo de código siguiente, puede crear un objeto de tipo Animal y establecer su tamaño en 2, y otro objeto cuyo tamaño puede establecer en 3. Sin embargo, hay una excepción importante a esta regla: el miembro estático.

 

Miembros estáticos y de instancia

Un miembro estático es un método o campo al que se puede obtener acceso sin hacer referencia a una instancia determinada de una clase. El método estático más común es Main, que es el punto de entrada de todos los programas de C#; tenga en cuenta que no es necesario crear una instancia de la clase contenedora para llamar al método Main. Otro método estático que se utiliza normalmente es WriteLine en la clase Console. Observe la diferencia de sintaxis cuando se tiene acceso a métodos estáticos; puede utilizar el nombre de clase, no el nombre de instancia, en la parte izquierda del operador de punto: Console.WriteLine.

Cuando declara un campo de clase estático, todas las instancias de esa clase compartirán ese campo. Si se declarara size como estático en el ejemplo de código siguiente y un objeto Animal cambiara el valor, éste se cambiaría para todos los objetos de tipo Animal.

Una clase estática es una cuyos miembros son todos estáticos. Las clases, métodos y campos estáticos son útiles en ciertos escenarios por razones de rendimiento y eficacia. Sin embargo, pueden surgir errores casi imperceptibles si se supone que un campo es un campo de instancia cuando de hecho es estático. Para obtener más información, vea Clases estáticas y sus miembros (Guía de programación de C#).

 

Clases y archivos

Cada programa de C# tiene al menos una clase. Al diseñar el programa, es una buena práctica, aunque no es un requisito, mantener una clase única en cada archivo de código fuente (.cs). Si utiliza el entorno de desarrollo integrado (IDE) de C# para crear las clases, éste, a la vez, creará un nuevo archivo de código en forma automática.

 

Encapsulación

Una clase representa normalmente las características de una cosa y las acciones que puede realizar. Por ejemplo, para representar un animal como una clase de C#, puede asignarle un tamaño, velocidad y fuerza, que se representan como números, y algunas funciones como MoveLeft(), MoveRight(), SpeedUp(), Stop(), etc., en las que podría escribir código para que el “animal” realice esas acciones. En C#, la clase animal tendría la apariencia siguiente:

 

C#  

public class Animal

{

private int size;

private float speed;

private int strength;

 

public void MoveLeft() // method

{

// code goes here…

}

 

// other methods go here…

} 

 

Si examina la .NET Framework Class Library (WinFX), observará que cada clase representa una “cosa”, como XmlDocument, String o Form, y cada una de ellas tiene varias acciones que puede realizar (métodos), características que se pueden leer y, a veces, modificar (propiedades) y notificaciones (eventos) que produce cuando se realiza una acción concreta. Los métodos, propiedades y eventos, junto con todas las demás variables internas y constantes (campos), se conocen como miembros de la clase.

La agrupación de miembros en clases no es sólo lógica, además permite ocultar datos y funciones a los que no desea que otro código tenga acceso. Este principio se conoce como encapsulación. Cuando explora las bibliotecas de clases de .NET Framework, está viendo sólo los miembros públicos de esas clases. Cada clase tiene probablemente miembros privados que esa clase o las relacionadas con ella utilizan internamente, pero su finalidad no es que los utilicen las aplicaciones. Cuando cree sus propias clases, decidirá qué miembros deberían ser públicos y cuáles deberían ser privados.

 

Herencia

Una clase puede heredar de otra, lo que significa que incluye todos los miembros, tanto públicos como privados, de la clase original, más los miembros adicionales que define. La clase original se denomina clase base y la nueva clase se denomina clase derivada. Una clase derivada se crea para representar algo que es un tipo más especializado de la clase base. Por ejemplo, podría definir una clase Cat que hereda de Animal. Cat puede hacer lo mismo que Animal, más una acción única adicional. El código C# tiene la apariencia siguiente:

 

C#  

public class Cat : Animal

{

public void Purr()

{

}

} 

 

La notación Cat : Animal indica que Cat hereda de Animal y, por tanto, Cat también tiene un método MoveLeft y tres variables privadas: size, speed y strength. Si define una clase SiameseCat que hereda de Cat, tendrá todos los miembros de Cat más todos los miembros de Animal.

 

Polimorfismo

En el campo de la programación, polimorfismo hace referencia a la capacidad de una clase derivada para redefinir o reemplazar los métodos que hereda de una clase base. Esto se hace cuando es necesario realizar una acción específica en un método que es diferente o no está definido en la clase base. Por ejemplo, como el método Animal.MoveLeft tiene que ser muy general a fin de que sea válido para todos los animales, probablemente es muy simple, por ejemplo: “cambiar la orientación para que la cabeza del anima apunte en la dirección X”. Sin embargo, en la clase Cat, esto podría no ser suficiente. Podría ser necesario especificar cómo Cat mueve sus patas y cola mientras gira. Además, si también se define una clase Fish o Bird, probablemente habría que reemplazar el método MoveLeft de diferentes maneras para cada una de esas clases. Como el comportamiento del método MoveLeft se puede personalizar para una clase concreta, el código que crea la clase y llama a sus métodos no tiene un método independiente para cada animal del mundo. Siempre y cuando el objeto herede de Amimal, el código de llamada puede llamar simplemente al método MoveLeft para que se invoque la versión del método propia del objeto.

 

 

Constructores

Cada clase tiene un constructor: un método que comparte el mismo nombre que la clase. Se llama al constructor cuando se crea un objeto basado en la definición de clase. Los constructores establecen normalmente los valores iniciales de las variables definidas en la clase. Esto no es necesario si los valores iniciales van a ser cero para los tipos de datos numéricos, false para los tipos de datos booleanos o null para los tipos de referencia, ya que estos tipos de datos se inicializan automáticamente.

Puede definir constructores con cualquier número de parámetros. Los constructores que no tienen parámetros se denominan constructores predeterminados. En el ejemplo siguiente se define una clase con un constructor predeterminado y un constructor que toma una cadena y, a continuación, se utilizan ambos:

 

C#  

class SampleClass

{

string greeting;

 

public SampleClass()

{

greeting = “Hello, World”;

}

 

public SampleClass(string message)

{

greeting = message;

}

 

public void SayHello()

{

System.Console.WriteLine(greeting);

}

}

 

class Program

{

static void Main(string[] args)

{

// Use default constructor.

SampleClass sampleClass1 = new SampleClass();

sampleClass1.SayHello();

 

// Use constructor that takes a string parameter.

SampleClass sampleClass2 = new SampleClass(“Hello, Mars”);

sampleClass2.SayHello();

}

} 

 

Sobrecarga de operadores

La creación de métodos diferentes con el mismo nombre, en la SampleClass() de ejemplo anterior, se denomina sobrecarga. El compilador sabe qué método utilizar porque la lista de argumentos, si existe, se proporciona cada vez que se crea un objeto. La sobrecarga puede hacer que el código sea más flexible y legible.

 

Destructores

Si ha utilizado C++, ya conoce los destructores. Debido al sistema de recolección automática de elementos no utilizados de C#, no es probable que tenga que implementar un destructor a menos que la clase utilice recursos no administrados.

 

Estructuras

Una estructura es un tipo que es similar a una clase de muchas maneras, excepto en que no admite la herencia.

 

ESTRUCTURAS

 

Una estructura en C# es similar a una clase, pero las estructuras carecen de ciertas características, como la herencia. Además, como una estructura es un tipo de valor, normalmente se puede crear más rápido que una clase. Si utiliza bucles de pequeñas dimensiones en los que se crean grandes cantidades de estructuras de datos nuevas, debe considerar la posibilidad de utilizar una estructura en vez de una clase. Las estructuras también se utilizan para encapsular grupos de campos de datos como las coordenadas de un punto en una cuadrícula o las dimensiones de un rectángulo.

 

Ejemplo

Este programa de ejemplo define una struct para almacenar una ubicación geográfica. También reemplaza el método ToString() para generar un resultado más útil cuando se muestra en la instrucción WriteLine. Como no hay ningún método en la struct, no hay ventaja para definirlo como una clase.

 

C#     

struct GeographicLocation

{

private double longitude;

private double latitude;

 

public GeographicLocation(double longitude, double latitude)

{

this.longitude = longitude;

this.latitude = latitude;

}

 

public override string ToString()

{

return System.String.Format(“Longitude: {0} degrees, Latitude: {1} degrees”, longitude, latitude);

}

}

 

class Program

{

static void Main()

{

GeographicLocation Seattle = new GeographicLocation(123, 47);

System.Console.WriteLine(“Position: {0}”, Seattle.ToString());

}

} 

 

Resultado

El resultado de este ejemplo presenta el siguiente aspecto:

Position: Longitude: 123 degrees, Latitude: 47 degrees

 

 

CONSTANTES Y VARIABLES

 

Una variable representa un valor numérico o de cadena o un objeto de una clase. El valor que la variable almacena puede cambiar, pero el nombre sigue siendo el mismo. Una variable es un tipo de campo. El código siguiente es un ejemplo sencillo de cómo declarar una variable de entero, asignarle un valor y, a continuación, asignarle un nuevo valor.

 

C#  

int x = 1; // x holds the value 1

x = 2; // now x holds the value 2 

 

En C#, las variables se declaran con un tipo de datos y una etiqueta concretos. Si hasta ahora sólo ha utilizado lenguajes con tipos definidos de forma imprecisa como JScript, estará acostumbrado a emplear el mismo tipo “var” para todas las variables, pero en C# tiene que especificar si la variable es de tipo int, float, byte, short u otro cualquiera entre más de 20 tipos de datos diferentes. El tipo especifica, entre otras cosas, la cantidad de memoria exacta que se debe asignar para almacenar el valor cuando la aplicación se ejecuta. El lenguaje C# fuerza ciertas reglas al convertir una variable de un tipo en otro.

 

C#  

int answer = 42;

string greeting = “Hello, World!”;

double bigNumber = 1e100;

 

System.Console.WriteLine(“{0} {1} {2}”, answer, greeting, bigNumber); 

 

Constantes

Una constante es otro tipo de campo. Contiene un valor que se asigna cuando se compila el programa y nunca cambia después. Las constantes se declaran con la palabra clave const; son útiles para que el código sea más legible.

 

C#  

const int speedLimit = 55;

const double pi = 3.14159265358979323846264338327950; 

 

Una variable readonly es como una constante pero su valor se asigna al iniciar el programa. Esto le permite establecer el valor basándose en alguna otra condición que no conoce hasta que se ejecuta el programa. Pero después de esa primera asignación, el valor no puede cambiar de nuevo mientras el programa se está ejecutando.

 

OPERADORES

 

En C#, los operadores tienen una sintaxis similar a otros lenguajes de programación de estilo C. Los operadores se utilizan para hacer cálculos, asignar valores a variables, comprobar la igualdad o desigualdad, y realizar otras operaciones.

En las secciones siguientes se muestran algunos de los operadores normalmente utilizados en C#.

 

Operadores de asignación e igualdad

En C#, el operador signo igual (=) tiene la misma funcionalidad que en C y C++:

 

Operador  

Finalidad  

=

Asigna un valor. 

==

Comprueba la igualdad. 

 

Ejemplo

C#  

int x = 100;

if (x == 100)

{

System.Console.WriteLine(“X is equal to 100”);

}

 

Operadores matemáticos y lógicos

La siguiente lista muestra los operadores matemáticos básicos en orden de prioridad. Utilice paréntesis para imponer otro orden.

 

Operador  

Finalidad  

*, /, %

Multiplicación, división, módulos 

+,

Suma, resta 

&

AND lógico 

^

XOR lógico 

|

OR lógico 

 

Ejemplo

C#  

int x = 1;

int y = x + 10 * 100; // multiplication first y = 1001

int z = (x + 10) * 100; // addition first z = 1100 

 

 

 

Operadores de incremento y decremento

Los accesos directos de estilo de C y C++ son compatibles, incluso los operadores de postfijo y prefijo, como se muestra en estos ejemplos:

 

Operador  

Finalidad  

v
++

Incrementar variable v por 1. 

v
+=
n

Incrementar variable v por n. 

v
*=
n

Multiplicar variable v por n. 

v
-=
n

Restar n de variable v. 

Ejemplo

C#  

int x = 0;

 

int y = x++; // x is 1, y is 0

 

System.Console.WriteLine(“{0} {1}”, x, y);

 

int z = ++x; // x is 2, z is 2

 

System.Console.WriteLine(“{0} {1}”, x, z); 

 

Operadores relacionales

Los siguientes operadores comparan dos valores y devuelven un resultado booleano:

Operador

Finalidad  

==

Comprobar igualdad. 

!=

Comprobar desigualdad. 

>

Mayor que 

<

Menor que 

>=

Mayor o igual que 

<=

Menor o igual que 

Ejemplo

C#  

int x = int.Parse(System.Console.ReadLine());

 

if (x > 100)

{

System.Console.WriteLine(“X is greater than 100”);

} 

 

Operadores lógicos de condición

Los operadores lógicos se utilizan para crear instrucciones de condición más flexibles combinando varias cláusulas:

 

Operador  

Finalidad  

&&

AND condicional. 

||

OR condicional. 

!

NOT condicional. 

Ejemplo

C#  

int x = int.Parse(System.Console.ReadLine());

 

if ((x >= 100) && (x <= 200))

{

System.Console.WriteLine(“X is between 100 and 200”);

} 

 

Operadores matemáticos más avanzados

Para realizar operaciones matemáticas más avanzadas, por ejemplo, trigonométricas, utilice la clase Math de .NET Framework. En este ejemplo, se utilizan los métodos Sin (seno) y Sqrt (raíz cuadrada) y la constante PI:

Ejemplo

C#  

double d = System.Math.Sin(System.Math.PI/2);

double e = System.Math.Sqrt(144); 

 

Sobrecarga de operadores

C# admite sobrecarga de operadores; esto permite volver a definir los operadores para que tengan más sentido cuando se utilizan con tipos de datos propios. En el siguiente ejemplo, se crea una estructura que almacena un solo día de la semana en un tipo de variable definido por una enumeración. El operador de suma se sobrecarga para que se pueda agregar un número entero de días al día actual y devolver un nuevo día de la semana. De este modo, domingo, con un día agregado, devuelve lunes.

Ejemplo

C#  

using System;

 

// Define an DayOfWeek data type

enum DayOfWeek { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };

 

// Define a struct to store the methods and operators

struct Day

{

private DayOfWeek day;

 

// The constructor for the struct

public Day(DayOfWeek initialDay)

{

day = initialDay;

}

 

// The overloaded + operator

public static Day operator +(Day lhs, int rhs)

{

int intDay = (int)lhs.day;

return new Day((DayOfWeek)((intDay + rhs) % 7));

}

 

// An overloaded ToString method

public override string ToString()

{

return day.ToString();

}

}

 

public class Program

{

static void Main()

{

// Create a new Days object called “today”

Day today = new Day(DayOfWeek.Sunday);

Console.WriteLine(today.ToString());

 

today = today + 1;

Console.WriteLine(today.ToString());

 

today = today + 14;

Console.WriteLine(today.ToString());

}

} 

 

 

BIFURCACIÓN Y TOMA DE DECISIONES

 

Cambiar el flujo de control en un programa en respuesta a algún tipo de entrada o valor calculado es una parte esencial de un lenguaje de programación. C# proporciona la capacidad para cambiar el flujo de control, ya sea en forma incondicional, pasando a una nueva ubicación en el código, o condicionalmente, realizando una prueba.

 

Comentarios

El tipo de bifurcación condicional más sencillo utiliza la construcción if. Se puede utilizar una cláusula else con la construcción if y anidar varias construcciones if.

 

C#  

using System;

 

class Program

{

static void Main()

{

int x = 1;

int y = 1;

 

 

if (x == 1)

Console.WriteLine(“x == 1”);

else

Console.WriteLine(“x != 1”);

 

 

if (x == 1)

{

if (y == 2)

{

Console.WriteLine(“x == 1 and y == 2”);

}

else

{

Console.WriteLine(“x == 1 and y != 2”);

}

}

}

} 

 

Nota 

A diferencia de C y C++, las instrucciones if requieren valores booleanos. Por ejemplo, no se permite tener una instrucción que no se evalúa con un simple True o False, como (a=10). En C#, no se puede sustituir el valor 0 por False y el valor 1 (o cualquier otro valor) por True.

 

Las instrucciones que siguen a las palabras clave if y else pueden ser una única línea de código, tal como se muestra en la primera instrucción if-else del ejemplo de código anterior, o un bloque de instrucciones entre llaves, tal como se muestra en la segunda instrucción if-else. Es posible anidar instrucciones if-else, pero generalmente se considera un mejor hábito de programación utilizar una instrucción switch en su lugar.

Una instrucción switch puede realizar varias acciones dependiendo del valor de una expresión determinada. El código entre la instrucción case y la palabra clave break se ejecuta si se cumple la condición. Si desea continuar el flujo de control con otra instrucción case, utilice la palabra clave goto.

 

C#  

using System;

 

class Program

{

static void Main()

{

int x = 3;

 

switch (x)

{

case 1:

Console.WriteLine(“x is equal to 1”);

break;

 

case 2:

Console.WriteLine(“x is equal to 2”);

break;

 

case 3:

goto default;

 

default:

Console.WriteLine(“x is equal to neither 1 nor 2”);

break;

}

}

} 

 

La expresión que la instrucción switch utiliza para determinar la instrucción case que se ejecutará debe utilizar Tipos de datos integrados (Visual C# Express), como int o string; no se pueden utilizar tipos más complejos definidos por el usuario.

A diferencia de Visual Basic, en C# la condición debe ser un valor constante. Por ejemplo, no se puede comparar la expresión con un intervalo de valores.

 

 

CADENAS

 

Una cadena de C# es un grupo de uno o más caracteres declarados mediante la palabra clave string, que es un método abreviado del lenguaje C# para la clase System.String. Las cadenas de C# son mucho más fáciles de utilizar y mucho menos propensas a errores de programación que las matrices de caracteres de C o C++.

Un literal de cadena se declara utilizando las comillas, como se muestra en el siguiente ejemplo:

 

C#  

string greeting = “Hello, World!”; 

 

Puede extraer subcadenas y concatenar cadenas de la siguiente manera:

 

C#  

string s1 = “orange”;

string s2 = “red”;

 

s1 += s2;

System.Console.WriteLine(s1); // outputs “orangered”

 

s1 = s1.Substring(2, 5);

System.Console.WriteLine(s1); // outputs “anger” 

 

Los objetos String son inmutables y, una vez creados, no se pueden cambiar. Los métodos que actúan sobre las cadenas, devuelven los nuevos objetos de cadena. De esta forma, por motivos de rendimiento, las grandes cantidades de concatenación o de manipulación de cadenas implicadas se deben llevar a cabo con la clase StringBuilder, como se muestra en los siguientes ejemplos de código.

 

Trabajar con cadenas

 

Carácter de escape

Los caracteres de escape como “\n” y (nueva línea) y “\t” (tabulador) se pueden incluir en cadenas. La línea:

 

C#  

string hello = “Hello\nWorld!”; 

equivale a:

Hello

World!

 

Si desea incluir una barra diagonal inversa, ésta debe estar precedida de otra barra diagonal inversa. La cadena siguiente:

C#  

string filePath = “\\\\My Documents\\”; 

equivale a:

\\My Documents\

 

El símbolo @

El símbolo @ especifica que se deben omitir los caracteres de escape y saltos de línea cuando se crea la cadena. Las dos cadenas siguientes son, por consiguiente, idénticas:

 

C#  

string p1 = “\\\\My Documents\\My Files\\”;

string p2 = @”\\My Documents\My Files\”; 

 

ToString()

Todos los tipos de datos integrados de C# ofrecen el método ToString, que convierte un valor en una cadena. Este método se puede utilizar para convertir valores numéricos en cadenas de la siguiente manera:

 

C#  

int year = 1999;

string msg = “Eve was born in ” + year.ToString();

System.Console.WriteLine(msg); // outputs “Eve was born in 1999”

 

Tener acceso a los caracteres individuales

Se obtiene acceso a los caracteres individuales contenidos en una cadena utilizando métodos como Substring, Replace,, Split y Trim.

 

C#  

string s3 = “Visual C# Express”;

 

System.Console.WriteLine(s3.Substring(7, 2)); // outputs “C#”

System.Console.WriteLine(s3.Replace(“C#”, “Basic”)); // outputs “Visual Basic Express” 

 

 

También es posible copiar los caracteres en una matriz de caracteres, tal como se muestra a continuación:

 

C#  

string s4 = “Hello, World”;

char[] arr = s4.ToCharArray(0, s4.Length);

 

foreach (char c in arr)

{

System.Console.Write(c); // outputs “Hello, World”

} 

 

 

 

Puede obtener acceso a los caracteres individuales de una cadena con un índice:

 

C#  

string s5 = “Printing backwards”;

 

for (int i = 0; i < s5.Length; i++)

{

System.Console.Write(s5[s5.Length – i – 1]); // outputs “sdrawkcab gnitnirP”

} 

 

Cambiar mayúsculas y minúsculas

Para cambiar las letras en una cadena a mayúsculas o minúsculas, se utiliza ToUpper() o ToLower(), de la siguiente forma:

 

C#  

string s6 = “Battle of Hastings, 1066”;

 

System.Console.WriteLine(s6.ToUpper()); // outputs “BATTLE OF HASTINGS 1066”

System.Console.WriteLine(s6.ToLower()); // outputs “battle of hastings 1066” 

 

Comparaciones

La manera más sencilla de comparar dos cadenas es utilizar los símbolos == y !=, que realizan una comparación con distinción entre mayúsculas y minúsculas.

 

C#  

string color1 = “red”;

string color2 = “green”;

string color3 = “red”;

 

if (color1 == color3)

{

System.Console.WriteLine(“Equal”);

}

if (color1 != color2)

{

System.Console.WriteLine(“Not equal”);

} 

 

Los objetos String también tienen un método CompareTo() que devuelve un valor entero, basado en si una cadena es menor < o mayor > que otra. Al comparar las cadenas, se utiliza el valor Unicode, y las minúsculas tienen un valor menor que las mayúsculas.

 

C#  

string s7 = “ABC”;

string s8 = “abc”;

 

if (s7.CompareTo(s8) > 0)

{

System.Console.WriteLine(“Greater-than”);

}

else

{

System.Console.WriteLine(“Less-than”);

} 

 

Para buscar una cadena dentro de otra, utilice IndexOf(). IndexOf() devuelve -1 si la cadena de búsqueda no se encuentra; en caso contrario devuelve el índice de la primera posición de la cadena, con base cero.

 

C#  

string s9 = “Battle of Hastings, 1066”;

 

System.Console.WriteLine(s9.IndexOf(“Hastings”)); // outputs 10

System.Console.WriteLine(s9.IndexOf(“1967”)); // outputs -1 

 

Dividir una cadena en subcadenas

Dividir una cadena en subcadenas es una tarea de programación común, semejante a dividir una frase en sus respectivas palabras. El método Split() toma una matriz de char de delimitadores (por ejemplo, un carácter de espacio) y devuelve una matriz de subcadenas. Para obtener acceso a esta matriz con foreach:

 

C#  

char[] delimit = new char[] { ‘ ‘ };

string s10 = “The cat sat on the mat.”;

foreach (string substr in s10.Split(delimit))

{

System.Console.WriteLine(substr);

} 

 

Este código genera cada palabra en una línea separada de la siguiente forma:

The

cat

sat

on

the

mat.

 

Utilizar StringBuilder

La clase StringBuilder crea un búfer de cadena que proporciona el mejor rendimiento si el programa realiza una gran manipulación de cadenas. La clase StringBuilder también permite reasignar caracteres individuales, algo que el tipo de datos de cadena integrado no admite.

En este ejemplo, se crea un objeto StringBuilder y el contenido se agrega poco a poco utilizando el método Append.

 

 

MATRICES Y COLECCIONES

 

El almacenamiento de grupos de elementos de datos relacionados es un requisito básico de casi todas las aplicaciones de software; las dos formas principales de almacenarlos son matrices y colecciones.

 

Matrices

Las matrices son colecciones de objetos del mismo tipo. Una matriz puede tener virtualmente cualquier longitud, lo que significa que se puede utilizar para almacenar miles o incluso millones de objetos, pero el tamaño se tiene que decidir al crearla. Se tiene acceso a cada elemento de la matriz mediante un índice, que es simplemente un número que indica la posición o ranura donde el objeto está almacenado. Las matrices se pueden utilizar para almacenar tipos de referencia y tipos de valor.

 

Matrices unidimensionales

Una matriz es una colección indizada de objetos. Una matriz unidimensional de objetos se declara así:

type[] arrayName;

 

A menudo, puede inicializar los elementos contenidos al mismo tiempo en la matriz de la siguiente manera:

 

C#  

int[] array = new int[5]; 

 

El valor predeterminado de los elementos numéricos de la matriz es cero y los elementos de referencia cambian de forma predeterminada a null, pero los valores se pueden inicializar durante la creación de la matriz de la manera siguiente:

 

C#  

int[] array1 = new int[5] { 1, 3, 5, 7, 9 }; 

 

O también:

 

C#  

int[] array2 = {1, 3, 5, 7, 9}; 

 

Las matrices utilizan los índices de base cero, por lo que el primer elemento en la matriz es el elemento 0.

 

C#  

string[] days = {“Sun”, “Mon”, “Tue”, “Wed”, “Thr”, “Fri”, “Sat”};

System.Console.WriteLine(days[0]); // Outputs “Sun” 

Matrices multidimensionales

 

Conceptualmente, una matriz multidimensional con dos dimensiones presenta la apariencia de una cuadrícula. Una matriz multidimensional con tres dimensiones presenta la apariencia de un cubo.

 

C#  

// declare multidimension array (two dimensions)

int[,] array2D = new int[2,3];

 

 

// declare and initialize multidimension array

int[,] array2D2 = { {1, 2, 3}, {4, 5, 6} };

 

 

// write elements in a multidimensional array

for (int i=0; i<2; i++)

{

for (int j=0; j<3; j++)

{

array2D[i,j] = (i + 1) * (j + 1);

}

}

 

 

// read elements in a multidimensional array

for (int i=0; i<2; i++)

{

for (int j=0; j<3; j++)

{

System.Console.Write(array2D[i,j]);

}

System.Console.WriteLine();

} 

 

Matrices escalonadas

Una variación de la matriz multidimensional es la matriz escalonada: una matriz de matrices. Una matriz escalonada es una matriz unidimensional y cada elemento es en sí mismo una matriz. No es necesario que todas las matrices de elementos sean del mismo tamaño.

Se declara una matriz escalonada así:

 

C#  

int[][] jaggedArray = new int[3][]; 

 

De esta manera se crea una matriz de tres matrices. Estas matrices se pueden inicializar así:

 

C#  

jaggedArray[0] = new int[5];

jaggedArray[1] = new int[4];

jaggedArray[2] = new int[2];

 

Utilizar la instrucción foreach

La instrucción foreach se utiliza a menudo para tener acceso a todos los elementos almacenados en una matriz:

 

C#  

int[] numbers = { 4, 5, 6, 1, 2, 3, -2, -1, 0 };

foreach (int i in numbers)

{

System.Console.WriteLine(i);

} 

 

Matrices de objetos

La creación de una matriz de objetos, en lugar de una matriz de tipos de datos simples como enteros, es un proceso que consta de dos partes. En primer lugar, se declara la matriz y, después, se deben crear los objetos almacenados en la matriz. En este ejemplo se crea una clase que define un CD de audio. A continuación se crea una matriz que almacena 20 CDs de audio.

 

C#  

namespace CDCollection

{

// Define a CD type.

class CD

{

private string album;

private string artist;

private int rating;

 

public string Album

{

get {return album;}

set {album = value;}

}

public string Artist

{

get {return artist;}

set {artist = value;}

}

public int Rating

{

get {return rating;}

set {rating = value;}

}

}

 

class Program

{

static void Main(string[] args)

{

// Create the array to store the CDs.

CD[] cdLibrary = new CD[20];

 

// Populate the CD library with CD objects.

for (int i=0; i<20; i++)

{

cdLibrary[i] = new CD();

}

 

// Assign details to the first album.

cdLibrary[0].Album = “See”;

cdLibrary[0].Artist = “The Sharp Band”;

cdLibrary[0].Rating = 10;

}

}

} 

 

Colecciones

Una matriz es simplemente una de muchas opciones para almacenar conjuntos de datos utilizando C#. La opción que elija depende de varios factores, entre los que se incluye cómo piensa manipular o tener acceso a los elementos. Por ejemplo, utilizar una lista suele ser más rápido que utilizar una matriz si es necesario insertar elementos al principio o en medio de la colección. Otros tipos de clases de colección incluyen mapa, árbol y pila; cada uno tiene sus propias ventajas. Para obtener más información, vea Tipos de colección utilizados normalmente, System.Collections y System.Collections.Generic.

En el ejemplo siguiente se muestra cómo utilizar la clase List <T>. Observe que a diferencia de la clase Array, los elementos se pueden insertar en medio de la lista. Este ejemplo restringe los elementos de la lista a fin de que sean cadenas.

 

C#  

public class TestCollections

{

public static void TestList()

{

System.Collections.Generic.List<string> sandwich = new System.Collections.Generic.List<string>();

 

sandwich.Add(“bacon”);

sandwich.Add(“tomato”);

 

sandwich.Insert(1, “lettuce”);

 

foreach (string ingredient in sandwich)

{

System.Console.WriteLine(ingredient);

}

}

} 

 

 

BUCLES

 

Un bucle es una instrucción o conjunto de instrucciones que se repite un número especificado de veces o hasta que se cumpla alguna condición. El tipo de bucle que elija dependerá de la tarea de programación y de su preferencia de codificación personal. Una de las principales diferencias entre C# y otros lenguajes como C++ es el bucle foreach, que está diseñado para simplificar la iteración en matrices o colecciones.

 

Bucles foreach

C# introduce una forma de crear bucles que puede resultar novedosa para los programadores en C++ y C: el bucle foreach. Ya no tendrá que crear una variable solo para indizar una matriz u otra estructura de datos como una colección, puesto que el bucle foreach hace parte de ese trabajo:

 

C#  

// An array of integers

int[] array1 = {0, 1, 2, 3, 4, 5};

 

foreach (int n in array1)

{

System.Console.WriteLine(n.ToString());

}

 

 

// An array of strings

string[] array2 = {“hello”, “world”};

 

foreach (string s in array2)

{

System.Console.WriteLine(s);

} 

 

Bucles for

Más abajo se muestra cómo crear el mismo bucle utilizando la palabra clave for:

 

Bucles while

Las versiones del bucle while tienen la apariencia siguiente:

 

C#  

// An array of integers

int[] array1 = {0, 1, 2, 3, 4, 5};

int x = 0;

 

while (x < 6)

{

System.Console.WriteLine(array1[x].ToString());

x++;

}

 

 

// An array of strings

string[] array2 = {“hello”, “world”};

int y = 0;

 

while (y < 2)

{

System.Console.WriteLine(array2[y]);

y++;

}

 

Bucles do-while

 

Los bucles do-while tienen esta apariencia:

 

C#  

// An array of integers

int[] array1 = {0, 1, 2, 3, 4, 5};

int x = 0;

 

do

{

System.Console.WriteLine(array1[x].ToString());

x++;

} while(x < 6);

 

 

// An array of strings

string[] array2 = {“hello”, “world”};

int y = 0;

 

do

{

System.Console.WriteLine(array2[y]);

y++;

} while(y < 2); 

 

 

ENUMERACION ES

 

C# permite crear un conjunto propio de constantes con nombre utilizando la palabra clave enum. Estos tipos de datos permiten declarar un conjunto de nombres u otros valores literales que definen todos los valores posibles que se pueden asignar a una variable.

Por ejemplo, si el programa utiliza los días de la semana, es posible crear un nuevo tipo llamado DayOfWeek. Se puede declarar una nueva variable del tipo DayOfWeek y asignarle un valor. La utilización de este tipo de datos permite que el código sea más legible y hace menos probable que se asigne a la variable un valor no válido o inesperado.

 

C#  

public enum DayOfWeek

{

Sunday = 0,

Monday = 1,

Tuesday = 2,

Wednesday = 3,

Thursday = 4,

Friday = 5,

Saturday = 6

}

 

class Program

{

static void Main()

{

DayOfWeek day = DayOfWeek.Monday;

int i = (int) DayOfWeek.Monday;

 

System.Console.WriteLine(day); // displays Monday

System.Console.WriteLine(i); // displays 1

}

} 

 

Técnicas de enumeración más avanzadas

 

A continuación, se muestran varias características de tipos de datos enum que pueden ser útiles.

 

Mostrar valores literales de enumeración

Si necesita tener acceso al nombre o las palabras que se está utilizando en el tipo de datos enum, puede hacerlo mediante el método ToString(), de la siguiente manera:

 

C#  

DayOfWeek day = DayOfWeek.Wednesday;

System.Console.WriteLine(day.ToString()); // displays Wednesday 

 

 

Establecer valores predeterminados

De manera predeterminada, el primer valor en el tipo enumerado es un cero. Se puede especificar un valor inicial diferente, de la siguiente forma:

 

C#  

enum Color { Red = 1, Yellow = 2, Blue = 3 }; 

 

De hecho, se pueden definir valores enteros únicos para todos los valores:

 

C#  

enum Medal { Gold = 30, Silver = 20, Bronze = 10 };

 

 

CONTROL DE ERRORES Y EXCEPCIONES

 

Cuando algo va mal mientras un programa de C# se está ejecutando, se inicia una excepción. Las excepciones detienen el flujo actual del programa, y si no se hace nada, el programa dejará de funcionar. Las excepciones se producen por un error en el programa, por ejemplo, si se divide un número por cero, o pueden ser el resultado de alguna entrada inesperada, por ejemplo, cuando un usuario selecciona un archivo que no existe. El programador debe habilitar su programa para que resuelva estos problemas sin bloquearse.

C# proporciona varias palabras clave, try, catch y finally, que permiten a los programas detectar las excepciones, resolverlas y seguir trabajando. Estas constituyen una herramienta muy útil para hacer más fiables sus aplicaciones.

 

Try y Catch

Las palabras clave try y catch se utilizan conjuntamente. Utilice try para delimitar el bloque de código que podría generar una excepción y catch para contener el código que se ejecutará si la excepción se genera. En este ejemplo, un cálculo crea una excepción al dividir por cero, que luego se detecta. Sin los bloques try y catch, en este programa se produciría un error.

 

C#  

class ProgramTryCatch

{

static void Main()

{

int x=0, y=0;

 

try

{

x = 10 / y;

}

 

catch (System.DivideByZeroException)

{

System.Console.WriteLine(“There was an attempt to divide by zero.”);

}

}

} 

 

Cuando se esté programando se recomienda ofrecer detalles sobre el tipo de excepción que detecta el código de catch. Cada try puede tener varias instrucciones catch, que se encargarán de excepciones diferentes.

 

Bloque finally

El código contenido en un bloque finally siempre se ejecuta, se produzca o no una excepción. Utilice el bloque finally para asegurarse de que se devuelven los recursos: por ejemplo, para asegurarse de que un archivo está cerrado.

 

C#  

try

{

// Code to try here.

}

catch (System.Exception ex)

{

// Code to handle exception here.

}

finally

{

// Code to execute after try (and possibly catch) here.

} 

 

Utilizar el control de excepciones

Las excepciones no son siempre una señal de que algo catastrófico ha ocurrido en el programa. A menudo es una forma más conveniente de dejar una sección de código que ya no es pertinente o es una señal de que un método no se ha realizado con éxito. Muchos de los métodos de clase de .NET Framework crean excepciones para advertir de una determinada condición.

 

También puede crear sus propias excepciones mediante la palabra clave throw. Por ejemplo:

 

C#  

class ProgramThrow

{

static void DoWork(int x)

{

if (x > 5)

{

throw new System.ArgumentOutOfRangeException(“X is too large”);

}

}

 

static void Main()

{

try

{

DoWork(10);

}

catch (System.ArgumentOutOfRangeException ex)

{

System.Console.WriteLine(ex.Message);

}

}

} 

 

Utilice las excepciones en sus programas cuando crea que existe la posibilidad de que surja alguna situación inesperada. Por ejemplo, al tratar con los datos introducidos por un usuario, al leer un archivo o al obtener acceso a alguna información de Internet.