Table of Contents Guía de programación de C# Dentro de un programa de C# Matrices Clases y structs Delegados Tipos de enumeración Eventos Excepciones y control de excepciones Registro y sistema de archivos Genéricos Indizadores Interfaces Interoperabilidad Main() y argumentos de la línea de comandos Espacios de nombres Tipos que aceptan valores NULL Conceptos de programación Instrucciones, expresiones y operadores Cadenas Tipos Código no seguro y punteros Comentarios de documentación XML
Guía de programación de C# 03/10/2017 • 1 min to read • Edit Online
Esta sección proporciona información detallada sobre las funcionalidades y características claves del lenguaje C# a las que C# puede acceder a través de .NET Framework. En la mayor parte de esta sección se supone que ya sabe algo sobre C# y que conoce los conceptos de programación generales. Si nunca ha programado ni ha trabajado con C#, puede visitar el tutorial interactivo Getting Started with C# (Introducción a C#), donde no se requiere ningún conocimiento previo de programación. Para obtener información sobre determinadas palabras clave, operadores y directivas de preprocesador, vea Referencia de C#. Para obtener información sobre la especificación del lenguaje C#, vea Especificación del lenguaje C#.
Secciones de programa Dentro de un programa de C# Main() y argumentos de la línea de comandos
Secciones de lenguaje Instrucciones, expresiones y operadores Tipos Clases y structs Interfaces Tipos de enumeración Delegados Matrices Cadenas Propiedades Indizadores Eventos Genéricos Iteradores Expresiones de consulta LINQ Expresiones lambda Espacios de nombres Tipos que aceptan valores NULL Código no seguro y punteros
Comentarios de documentación XML
Secciones de la plataforma Dominios de aplicación (C# y Visual Basic) Ensamblados y Caché global de ensamblados Atributos Colecciones Excepciones y control de excepciones Registro y sistema de archivos (Guía de programación de C#) Interoperabilidad Reflexión
Vea también Referencia de C# C#
Dentro de un programa de C# 03/10/2017 • 1 min to read • Edit Online
En esta sección, se describe la estructura general de un programa de C# y se incluye el ejemplo estándar "Hola mundo".
En esta sección Hello World, su primer programa Estructura general de un programa de C#
Secciones relacionadas Introducción a C# Guía de programación de C# Referencia de C#
Aplicaciones de ejemplo de C#
Especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Vea también Guía de programación de C#
Matrices (Guía de programación de C#) 03/10/2017 • 1 min to read • Edit Online
Puede almacenar varias variables del mismo tipo en una estructura de datos de matriz. Puede declarar una matriz mediante la especificación del tipo de sus elementos. type[] arrayName;
Los ejemplos siguientes crean matrices unidimensionales, multidimensionales y escalonadas: class LINQQueryExpressions { static void Main() { // Specify the data source. int[] scores = new int[] { 97, 92, 81, 60 }; // Define the query expression. IEnumerable scoreQuery = from score in scores where score > 80 select score; // Execute the query. foreach (int i in scoreQuery) { Console.Write(i + " "); } } } // Output: 97 92 81
Información general de las matrices Una matriz tiene las propiedades siguientes: Puede ser una matriz unidimensional, multidimensional o escalonada. El número de dimensiones y la longitud de cada dimensión se establecen al crear la instancia de matriz. No se pueden cambiar estos valores durante la vigencia de la instancia. Los valores predeterminados de los elementos numéricos de matriz se establecen en cero y los elementos de referencia se establecen 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 indexan con cero: una matriz con
n
elementos se indexa de
0
a
n-1
.
Los elementos de una matriz puede ser cualquier tipo, incluido un tipo de matriz. Los tipos de matriz son tipos de referencia que proceden del tipo base abstracto Array. Como este tipo implementa IEnumerable y IEnumerable, puede usar la iteración foreach en todas las matrices de C#.
Secciones relacionadas
Matrices como objetos Utilizar foreach con matrices Pasar matrices como argumentos Pasar matrices mediante Ref y Out
Especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Vea también Guía de programación de C# Colecciones Tipo de colección de matrices
Clases y structs (Guía de programación de C#) 03/10/2017 • 6 min to read • Edit Online
Las clases y estructuras son dos de las construcciones básicas de Common Type System en .NET Framework. Cada una de ellas es básicamente una estructura de datos que encapsula un conjunto de datos y comportamientos que forman un conjunto como una unidad lógica. Los datos y comportamientos son los miembros de la clase o estructura, e incluyen sus métodos, propiedades y eventos, entre otros elementos, como se muestra más adelante en este tema. Una declaración de clase o estructura es como un plano que se utiliza para crear instancias u objetos en tiempo de ejecución. Si define una clase o estructura llamada Person , Person es el nombre del tipo. Si declara e inicializa una variable p de tipo Person , se dice que p es un objeto o instancia de Person . Se pueden crear varias instancias del mismo tipo Person , y cada instancia tiene diferentes valores en sus propiedades y campos. Una clase es un tipo de referencia. Cuando se crea un objeto de la clase, la variable a la que se asigna el objeto contiene solo una referencia a esa memoria. Cuando la referencia de objeto se asigna a una nueva variable, la nueva variable hace referencia al objeto original. Los cambios realizados en una variable se reflejan en la otra variable porque ambas hacen referencia a los mismos datos. Una estructura es un tipo de valor. Cuando se crea una estructura, la variable a la que se asigna la estructura contiene los datos reales de ella. Cuando la estructura se asigna a una nueva variable, se copia. Por lo tanto, la nueva variable y la variable original contienen dos copias independientes de los mismos datos. Los cambios realizados en una copia no afectan a la otra copia. En general, las clases se utilizan para modelar comportamientos más complejos, o datos que se prevén modificar después de haber creado un objeto de clase. Las estructuras son más adecuadas para las estructuras de datos pequeñas que contienen principalmente datos que no se prevén modificar después de haber creado la estructura. Para más información, vea Clases, Objectos y Estructuras.
Ejemplo En el ejemplo siguiente, CustomClass en el espacio de nombres ProgrammingGuide tiene tres miembros: un constructor de instancia, una propiedad denominada Number y un método denominado Multiply . El método Main de la clase Program crea una instancia (objeto) de CustomClass , y se puede acceder a la propiedad y al método del objeto mediante una notación de puntos.
using System; namespace ProgrammingGuide { // Class definition. public class CustomClass { // Class members. // // Property. public int Number { get; set; } // Method. public int Multiply(int num) { return num * Number; } // Instance Constructor. public CustomClass() { Number = 0; } } // Another class definition that contains Main, the program entry point. class Program { static void Main(string[] args) { // Create an object of type CustomClass. CustomClass custClass = new CustomClass(); // Set the value of the public property. custClass.Number = 27; // Call the public method. int result = custClass.Multiply(4); Console.WriteLine($"The result is {result}."); } } } // The example displays the following output: // The result is 108.
Encapsulación A veces se hace referencia a la encapsulación como el primer pilar o principio de la programación orientada a objetos. Según el principio de encapsulación, una clase o una estructura pueden especificar hasta qué punto se puede acceder a sus miembros para codificar fuera de la clase o la estructura. No se prevé el uso de los métodos y las variables fuera de la clase, o el ensamblado puede ocultarse para limitar el potencial de los errores de codificación o de los ataques malintencionados. Para más información sobre las clases, vea Clases y Objetos. Miembros Todos los métodos, campos, constantes, propiedades y eventos deben declararse dentro de un tipo; se les denomina miembros del tipo. En C#, no hay métodos ni variables globales como en otros lenguajes. Incluso un punto de entrada del programa, el método Main , debe declararse dentro de una clase o estructura. La lista siguiente incluye los diversos tipos de miembros que se pueden declarar en una clase o estructura. Campos
Constantes Propiedades Métodos Constructores Eventos Finalizadores Indizadores Operadores Tipos anidados Accesibilidad Algunos métodos y propiedades están diseñados para ser invocables y accesibles desde el código fuera de la clase o la estructura, lo que se conoce como código de cliente. Otros métodos y propiedades pueden estar indicados exclusivamente para utilizarse en la propia clase o estructura. Es importante limitar la accesibilidad del código, a fin de que solo el código de cliente previsto pueda acceder a él. Puede usar los modificadores de acceso public, protected, internal, protected internal y private para especificar hasta qué punto los tipos y sus miembros son accesibles para el código de cliente. La accesibilidad predeterminada es private . Para más información, vea Modificadores de acceso. Herencia Las clases (pero no las estructuras) admiten el concepto de herencia. Una clase que deriva de otra clase (la clase base) contiene automáticamente todos los miembros públicos, protegidos e internos de la clase base, salvo sus constructores y finalizadores. Para más información, vea Herencia y Polimorfismo. Las clases pueden declararse como abstract, lo que significa que uno o varios de sus métodos no tienen ninguna implementación. Aunque no se pueden crear instancias de clases abstractas directamente, pueden servir como clases base para otras clases que proporcionan la implementación que falta. Las clases también pueden declararse como sealed para evitar que otras clases hereden de ellas. Para más información, vea Clases y miembros de clase abstractos y sellados. Interfaces Las clases y las estructuras pueden heredar varias interfaces. Heredar de una interfaz significa que el tipo implementa todos los métodos definidos en la interfaz. Para más información, vea Interfaces. Tipos genéricos Las clases y estructuras pueden definirse con uno o varios parámetros de tipo. El código de cliente proporciona el tipo cuando crea una instancia del tipo. Por ejemplo, la clase List del espacio de nombres System.Collections.Generic se define con un parámetro de tipo. El código de cliente crea una instancia de List o List para especificar el tipo que contendrá la lista. Para más información, vea Genéricos. Tipos estáticos Las clases (pero no las estructuras) pueden declararse como static. Una clase estática puede contener solo miembros estáticos y no se puede crear una instancia de ellos con la palabra clave new. Una copia de la clase se carga en memoria cuando se carga el programa, y sus miembros son accesibles a través del nombre de clase. Las clases y estructuras pueden contener miembros estáticos. Para más información, vea Clases estáticas y sus miembros. Tipos anidados Una clase o estructura se puede anidar dentro de otra clase o estructura. Para obtener más información, consulte
Tipos anidados. Tipos parciales Puede definir parte de una clase, estructura o método en un archivo de código y otra parte en un archivo de código independiente. Para más información, vea Clases y métodos parciales. Inicializadores de objeto Puede crear instancias de objetos de clase o estructura y de colecciones de objetos e iniciarlizarlos, sin llamar de forma explícita a su constructor. Para más información, vea Inicializadores de objeto y de colección. Tipos anónimos En situaciones donde no es conveniente o necesario crear una clase con nombre, por ejemplo al rellenar una lista con estructuras de datos que no tiene que conservar o pasar a otro método, utilice los tipos anónimos. Para más información, vea Tipos anónimos. métodos de extensión. Puede "extender" una clase sin crear una clase derivada mediante la creación de un tipo independiente cuyos métodos pueden llamarse como si pertenecieran al tipo original. Para más información, vea Métodos de extensión. Variables locales con asignación implícita de tipos Dentro de un método de clase o estructura, puede utilizar tipos implícitos para indicar al compilador que determine el tipo correcto en tiempo de compilación. Para más información, vea Variables locales con asignación implícita de tipos.
Especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Vea también Guía de programación de C#
Delegados (Guía de programación de C#) 03/10/2017 • 2 min to read • Edit Online
Un delegado es un tipo que representa referencias a métodos con una lista de parámetros determinada y un tipo de valor devuelto. Cuando se crea una instancia de un delegado, puede asociar su instancia a cualquier método mediante una signatura compatible y un tipo de valor devuelto. Puede invocar (o llamar) al método a través de la instancia del delegado. Los delegados se utilizan para pasar métodos como argumentos a otros métodos. Los controladores de eventos no son más que métodos que se invocan a través de delegados. Cree un método personalizado y una clase, como un control de Windows, podrá llamar al método cuando se produzca un determinado evento. En el siguiente ejemplo se muestra una declaración de delegado: public delegate int PerformCalculation(int x, int y);
Cualquier método de cualquier clase o struct accesible que coincida con el tipo de delegado se puede asignar al delegado. El método puede ser estático o de instancia. Esto permite cambiar las llamadas a métodos mediante programación y agregar nuevo código a las clases existentes. NOTA En el contexto de la sobrecarga de métodos, la signatura de un método no incluye el valor devuelto. Sin embargo, en el contexto de los delegados, la signatura sí lo incluye. En otras palabras, un método debe tener el mismo tipo de valor devuelto que el delegado.
Esta capacidad de hacer referencia a un método como parámetro hace que los delegados sean idóneos para definir métodos de devolución de llamada. Por ejemplo, una referencia a un método que compara dos objetos podría pasarse como argumento a un algoritmo de ordenación. Dado que el código de comparación está en un procedimiento independiente, el algoritmo de ordenación se puede escribir de manera más general.
Información general sobre los delegados Los delegados tienen las propiedades siguientes: Los delegados son como los punteros de función de C++, pero tienen seguridad de tipos. Los delegados permiten pasar los métodos como parámetros. Los delegados pueden usarse para definir métodos de devolución de llamada. Los delegados pueden encadenarse entre sí; por ejemplo, se puede llamar a varios métodos en un solo evento. No es necesario que los métodos coincidan exactamente con el tipo de delegado. Para obtener más información, consulte Usar varianza en delegados. La versión 2.0 de C# presentó el concepto de Métodos anónimos, los cuales permiten pasar bloques de código como parámetros en lugar de un método definido por separado. En C# 3.0 se presentaron las expresiones lambda como una manera más concisa de escribir bloques de código alineado. Tanto los métodos anónimos como las expresiones lambda (en ciertos contextos) se compilan en tipos de delegado. Juntas, estas características se conocen ahora como funciones anónimas. Para obtener más información
sobre las expresiones lambda, consulte Funciones anónimas.
En esta sección Utilizar delegados Cuándo usar delegados en lugar de interfaces (Guía de programación de C#) Delegados con métodos con nombre y delegados con métodos anónimos Métodos anónimos Uso de varianza en delegados Cómo: Combinar delegados (delegados de multidifusión) Cómo: Declarar un delegado, crear instancias del mismo y utilizarlo
Especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Capítulos destacados del libro Delegates, Events, and Lambda Expressions (Delegados, eventos y expresiones lambda) en C# 3.0 Cookbook, Third Edition: More than 250 solutions for C# 3.0 programmers Delegates and Events (Delegados, eventos y expresiones lambda) en Learning C# 3.0: Master the fundamentals of C# 3.0
Vea también Delegate Guía de programación de C# Eventos
Tipos de enumeración (Guía de programación de C#) 03/10/2017 • 4 min to read • Edit Online
Un tipo de enumeración (también denominado enumeración) proporciona una manera eficaz de definir un conjunto de constantes enteras con nombre que se pueden asignar a una variable. Por ejemplo, suponga que tiene que definir una variable cuyo valor representará un día de la semana. Dicha variable solo almacenará siete valores significativos. Para definir esos valores, puede usar un tipo de enumeración, que se declara mediante la palabra clave enum. enum Day { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }; enum Month : byte { Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec };
De forma predeterminada, el tipo subyacente de cada elemento de la enumeración es int. Puede especificar otro tipo numérico entero mediante el uso del signo de dos puntos, como se muestra en el ejemplo anterior. Para obtener una lista completa de los tipos posibles, vea enum (Referencia de C#). Puede comprobar los valores numéricos subyacentes mediante la conversión al tipo subyacente, como se muestra en el ejemplo siguiente. Day today = Day.Monday; int dayNumber =(int)today; Console.WriteLine("{0} is day number #{1}.", today, dayNumber); Month thisMonth = Month.Dec; byte monthNumber = (byte)thisMonth; Console.WriteLine("{0} is month number #{1}.", thisMonth, monthNumber); // Output: // Monday is day number #1. // Dec is month number #11.
Estas son las ventajas de usar una enumeración en lugar de un tipo numérico: Se especifica claramente para el código de cliente qué valores son válidos para la variable. En Visual Studio, IntelliSense muestra los valores definidos. Cuando no se especifican valores para los elementos de la lista de enumeradores, los valores se incrementan automáticamente en 1. En el ejemplo anterior, Day.Sunday tiene un valor de 0, Day.Monday tiene un valor de 1, y así sucesivamente. Cuando cree un nuevo objeto Day , tendrá un valor predeterminado de Day.Sunday (0) si no le asigna explícitamente un valor. Cuando cree una enumeración, seleccione el valor predeterminado más lógico y asígnele un valor de cero. Esto hará que todas las enumeraciones tengan ese valor predeterminado si no se les asigna explícitamente un valor cuando se crean. Si la variable definidos por
es de tipo Day , solo puede asignarle (sin una conversión explícita) uno de los valores Day . Si el día de la reunión cambia, puede asignarle un nuevo valor de Day a meetingDay :
meetingDay
Day meetingDay = Day.Monday; //... meetingDay = Day.Friday;
NOTA Es posible asignar un valor entero cualquiera a meetingDay . Por ejemplo, esta línea de código no genera un error: meetingDay = (Day) 42 . Pero no debe hacerlo, ya que la expectativa implícita es que una variable de enumeración contenga solamente uno de los valores definidos por la enumeración. La acción de asignar un valor arbitrario a una variable de un tipo de enumeración aumenta el riesgo de errores.
Puede asignar cualquier valor a los elementos de la lista de enumeradores de un tipo de enumeración, y también puede usar valores calculados: enum MachineState { PowerOff = 0, Running = 5, Sleeping = 10, Hibernating = Sleeping + 5 }
Tipos de enumeración como marcas de bits Puede usar un tipo de enumeración para definir marcas de bits, lo que permite que una instancia del tipo de enumeración almacene cualquier combinación de los valores que se definen en la lista de enumeradores. (Obviamente, es posible que algunas combinaciones no sean significativas o no se permitan en el código del programa). Para crear una enumeración de marcas de bits, aplique el atributo System.FlagsAttribute y defina los valores de forma adecuada para que se puedan realizar en ellos operaciones bit a bit AND , OR , NOT y XOR . En una enumeración de marcas de bits, incluya una constante con nombre con un valor de cero que signifique "no se establecen marcas". No le asigne a una marca un valor de cero si no significa "no se establecen marcas". En el ejemplo siguiente, se define otra versión de la enumeración Day , denominada Days . Days tiene el atributo Flags y a cada valor se le asigna la siguiente potencia de 2 superior. Esto le permite crear una variable Days cuyo valor es Days.Tuesday | Days.Thursday . [Flags] enum Days { None = 0x0, Sunday = 0x1, Monday = 0x2, Tuesday = 0x4, Wednesday = 0x8, Thursday = 0x10, Friday = 0x20, Saturday = 0x40 } class MyClass { Days meetingDays = Days.Tuesday | Days.Thursday; }
Para establecer una marca en una enumeración, use el operador bit a bit siguiente:
OR
tal como se muestra en el ejemplo
// Initialize with two flags using bitwise OR. meetingDays = Days.Tuesday | Days.Thursday; // Set an additional flag using bitwise OR. meetingDays = meetingDays | Days.Friday; Console.WriteLine("Meeting days are {0}", meetingDays); // Output: Meeting days are Tuesday, Thursday, Friday // Remove a flag using bitwise XOR. meetingDays = meetingDays ^ Days.Tuesday; Console.WriteLine("Meeting days are {0}", meetingDays); // Output: Meeting days are Thursday, Friday
Para determinar si se ha establecido una marca específica, use una operación bit a bit el ejemplo siguiente:
AND
, tal como se muestra en
// Test value of flags using bitwise AND. bool test = (meetingDays & Days.Thursday) == Days.Thursday; Console.WriteLine("Thursday {0} a meeting day.", test == true ? "is" : "is not"); // Output: Thursday is a meeting day.
Para obtener más información sobre lo que debe tener en cuenta para definir tipos de enumeraciones con el atributo System.FlagsAttribute, vea System.Enum.
Usar los métodos System.Enum para detectar y manipular valores de enumeración Todas las enumeraciones son instancias del tipo System.Enum. No se pueden derivar clases nuevas de System.Enum, pero puede usar sus métodos para detectar información relacionada y manipular los valores de una instancia de enumeración. string s = Enum.GetName(typeof(Day), 4); Console.WriteLine(s); Console.WriteLine("The values of the Day Enum are:"); foreach (int i in Enum.GetValues(typeof(Day))) Console.WriteLine(i); Console.WriteLine("The names of the Day Enum are:"); foreach (string str in Enum.GetNames(typeof(Day))) Console.WriteLine(str);
Para obtener más información, consulta System.Enum. También puede crear un método nuevo para una enumeración mediante un método de extensión. Para obtener más información, vea Cómo: Crear un método nuevo para una enumeración.
Vea también System.Enum Guía de programación de C# enum
Eventos (Guía de programación de C#) 03/10/2017 • 2 min to read • Edit Online
Cuando ocurre algo interesante, los eventos habilitan una clase u objeto para notificarlo a otras clases u objetos. La clase que envía (o genera) el evento recibe el nombre de publicador y las clases que reciben (o controlan) el evento se denominan suscriptores. En una aplicación web o una aplicación de Windows Forms en C# típica, se puede suscribir a eventos generados por controles, como botones y cuadros de lista. Puede usar el entorno de desarrollo integrado (IDE) de Visual C# para examinar los eventos que publica un control y seleccionar los que quiera administrar. El IDE agrega automáticamente un método de controlador de eventos vacío y el código para suscribirse al evento. Para obtener más información, vea How to: Subscribe to and Unsubscribe from Events (Cómo: Suscribir y cancelar la suscripción a eventos [Guía de programación de C#]).
Información general sobre eventos Los eventos tienen las siguientes propiedades: El publicador determina el momento en el que se genera un evento; los suscriptores determinan la acción que se lleva a cabo en respuesta al evento. Un evento puede tener varios suscriptores. Un suscriptor puede controlar varios eventos de varios publicadores. Nunca se generan eventos que no tienen suscriptores. Los eventos se suelen usar para indicar acciones del usuario, como los clics de los botones o las selecciones de menú en las interfaces gráficas de usuario. Cuando un evento tiene varios suscriptores, los controladores de eventos se invocan sincrónicamente cuando se genera un evento. Para invocar eventos de forma asincrónica, consulte Calling Synchronous Methods Asynchronously. En la biblioteca de clases .NET Framework , los eventos se basan en el delegado EventHandler y en la clase base EventArgs .
Secciones relacionadas Para obtener más información, consulte: Cómo: Suscribir y cancelar la suscripción a eventos Cómo: Publicar eventos que cumplan las directrices de .NET Framework Cómo: Producir eventos de una clase base en clases derivadas Cómo: Implementar eventos de interfaz Sincronización de subprocesos Cómo: Utilizar un diccionario para almacenar instancias de eventos Cómo: Implementar descriptores de acceso de eventos personalizados
Especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Capítulos destacados del libro Delegates, Events, and Lambda Expressions (Delegados, eventos y expresiones lambda) en C# 3.0 Cookbook, Third Edition: More than 250 solutions for C# 3.0 programmers Delegates and Events (Delegados, eventos y expresiones lambda) en Learning C# 3.0: Master the fundamentals of C# 3.0
Vea también EventHandler Guía de programación de C# Delegados Crear controladores de eventos en Windows Forms Programación multiproceso con el modelo asincrónico basado en eventos
Excepciones y control de excepciones (Guía de programación de C#) 03/10/2017 • 3 min to read • Edit Online
Las características de control de excepciones del lenguaje C# le ayudan a afrontar cualquier situación inesperada o excepcional que se produce cuando se ejecuta un programa. El control de excepciones usa las palabras clave try , catch y finally para intentar realizar acciones que pueden no completarse correctamente, para controlar errores cuando decide que es razonable hacerlo y para limpiar recursos más adelante. Las excepciones las puede generar Common Language Runtime (CLR), .NET Framework, cualquier biblioteca de terceros o el código de aplicación. Las excepciones se crean mediante el uso de la palabra clave throw . En muchos casos, una excepción la puede no producir un método al que el código ha llamado directamente, sino otro método más bajo en la pila de llamadas. Cuando esto sucede, CLR desenredar la pila, busca un método con un bloque catch para el tipo de excepción específico y ejecuta el primer bloque catch que encuentra. Si no encuentra ningún bloque catch adecuado en cualquier parte de la pila de llamadas, finalizará el proceso y mostrará un mensaje al usuario. En este ejemplo, un método prueba a hacer la división entre cero y detecta el error. Sin el control de excepciones, este programa finalizaría con un error DivideByZeroException no controlada. class ExceptionTest { static double SafeDivision(double x, double y) { if (y == 0) throw new System.DivideByZeroException(); return x / y; } static void Main() { // Input for test purposes. Change the values to see // exception handling behavior. double a = 98, b = 0; double result = 0; try { result = SafeDivision(a, b); Console.WriteLine("{0} divided by {1} = {2}", a, b, result); } catch (DivideByZeroException e) { Console.WriteLine("Attempted divide by zero."); } } }
Información general sobre excepciones Las excepciones tienen las siguientes propiedades: Las excepciones son tipos que derivan en última instancia de Use un bloque
try
System.Exception
.
alrededor de las instrucciones que pueden producir excepciones.
Una vez que se produce una excepción en el bloque try , el flujo de control salta al primer controlador de excepciones asociado que está presente en cualquier parte de la pila de llamadas. En C#, la palabra clave catch se utiliza para definir un controlador de excepciones. Si no hay ningún controlador de excepciones para una excepción determinada, el programa deja de ejecutarse con un mensaje de error. No detecte una excepción a menos que pueda controlarla y dejar la aplicación en un estado conocido. Si se detecta System.Exception , reinícielo con la palabra clave throw al final del bloque catch . Si un bloque catch define una variable de excepción, puede utilizarla para obtener más información sobre el tipo de excepción que se ha producido. Las excepciones puede generarlas explícitamente un programa con la palabra clave
throw
.
Los objetos de excepción contienen información detallada sobre el error, como el estado de la pila de llamadas y una descripción de texto del error. El código de un bloque finally se ejecuta incluso si se produce una excepción. Use un bloque finally para liberar recursos, por ejemplo, para cerrar las secuencias o los archivos que se abrieron en el bloque try . Las excepciones administradas de .NET Framework se implementan en el mecanismo de control de excepciones estructurado de Win32. Para más información, vea Control de excepciones estructurado (C/C++) y A Crash Course on the Depths of Win32 Structured Exception Handling (Curso intensivo sobre los aspectos específicos del control de excepciones estructurado de Win32).
Secciones relacionadas Vea los temas siguientes para obtener más información sobre excepciones y control de excepciones: Utilizar excepciones Control de excepciones Crear y producir excepciones Excepciones generadas por el compilador Control de una excepción mediante Try y Catch (Guía de programación de C#) Cómo: Ejecutar código de limpieza mediante finally
Especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Vea también SystemException Guía de programación de C# Palabras clave de C# throw try-catch try-finally try-catch-finally Excepciones
Jerarquía de excepciones Escritura segura de código .NET Minivolcados para excepciones concretas
Registro y sistema de archivos (Guía de programación de C#) 03/10/2017 • 1 min to read • Edit Online
Los temas siguientes tratan cómo usar C# y .NET Framework para realizar diversas operaciones básicas en los archivos, las carpetas y el Registro.
En esta sección TÍTULO
DESCRIPCIÓN
Cómo: Recorrer en iteración un árbol de directorio
Muestra cómo realizar una iteración manual a través de un árbol de directorio.
Cómo: Obtener información sobre archivos, carpetas y unidades
Muestra cómo recuperar información como las horas de creación y el tamaño, así como sobre archivos, carpetas y unidades.
Cómo: Crear archivos o carpetas
Muestra cómo crear un archivo o una carpeta nuevos.
Cómo: Copiar, eliminar y mover archivos y carpetas (Guía de programación de C#)
Muestra cómo copiar, eliminar y mover archivos y carpetas.
Cómo: Proporcionar un cuadro de diálogo de progreso para operaciones de archivos
Muestra cómo mostrar un cuadro de diálogo de progreso estándar de Windows para determinadas operaciones de archivo.
Cómo: Escribir en un archivo texto
Muestra cómo escribir en un archivo de texto.
Cómo: Leer de un archivo de texto
Muestra cómo leer de un archivo de texto.
Cómo: Leer un archivo de texto línea a línea
Muestra cómo recuperar el texto de un archivo línea a línea.
Cómo: Crear una clave en el Registro
Muestra cómo escribir una clave en el registro del sistema.
Secciones relacionadas E/S de archivos y secuencias Cómo: Copiar, eliminar y mover archivos y carpetas (Guía de programación de C#) Guía de programación de C# Archivos, carpetas y unidades System.IO
Genéricos (Guía de programación de C#) 03/10/2017 • 1 min to read • Edit Online
Los genéricos se han agregado a la versión 2.0 del lenguaje C# y Common Language Runtime (CLR). Los genéricos introducen en .NET Framework el concepto de parámetros de tipo, lo que le permite diseñar clases y métodos que aplazan la especificación de uno o varios tipos hasta que el código de cliente declare y cree una instancia de la clase o el método. Por ejemplo, al usar un parámetro de tipo genérico T puede escribir una clase única que otro código de cliente puede usar sin incurrir en el costo o riesgo de conversiones en tiempo de ejecución u operaciones de conversión boxing, como se muestra aquí: // Declare the generic class. public class GenericList { void Add(T input) { } } class TestGenericList { private class ExampleClass { } static void Main() { // Declare a list of type int. GenericList list1 = new GenericList(); // Declare a list of type string. GenericList list2 = new GenericList(); // Declare a list of type ExampleClass. GenericList list3 = new GenericList(); } }
Información general sobre los genéricos Use tipos genéricos para maximizar la reutilización del código, la seguridad de tipos y el rendimiento. El uso más común de los genéricos es crear clases de colección. La biblioteca de clases .NET Framework contiene varias clases de colección genéricas nuevas en el espacio de nombres System.Collections.Generic. Estas se deberían usar siempre que sea posible en lugar de clases como ArrayList en el espacio de nombres System.Collections. Puede crear sus propias interfaces, clases, métodos, eventos y delegados genéricos. Puede limitar las clases genéricas para habilitar el acceso a métodos en tipos de datos determinados. Puede obtener información sobre los tipos que se usan en un tipo de datos genérico en tiempo de ejecución mediante la reflexión.
Secciones relacionadas Para obtener más información: Introducción a los genéricos Ventajas de los genéricos
Parámetros de tipo genérico Restricciones de tipos de parámetros Clases genéricas Interfaces genéricas Métodos genéricos Delegados genéricos Diferencias entre plantillas de C++ y tipos genéricos de C# Genéricos y reflexión Genéricos en el motor en tiempo de ejecución Tipos genéricos en la biblioteca de clases de .NET Framework
Especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#.
Vea también System.Collections.Generic Guía de programación de C# Tipos
Indizadores (Guía de programación de C#) 03/10/2017 • 3 min to read • Edit Online
Los indizadores permiten indizar las instancias de una clase o struct como matrices. El valor indizado se puede establecer o recuperar sin especificar explícitamente un miembro de tipo o de instancia. Son similares a propiedades, excepto en que sus descriptores de acceso usan parámetros. En el ejemplo siguiente se define una clase genérica con métodos de descriptor de acceso get y set sencillos para asignar y recuperar valores. La clase Program crea una instancia de esta clase para almacenar cadenas. using System; class SampleCollection { // Declare an array to store the data elements. private T[] arr = new T[100]; // Define the indexer to allow client code to use [] notation. public T this[int i] { get { return arr[i]; } set { arr[i] = value; } } } class Program { static void Main() { var stringCollection = new SampleCollection(); stringCollection[0] = "Hello, World"; Console.WriteLine(stringCollection[0]); } } // The example displays the following output: // Hello, World.
NOTA Para obtener más ejemplos, vea Secciones relacionadas.
Definiciones de cuerpos de expresión Es habitual que un descriptor de acceso get o set de un indizador conste de una única instrucción que devuelve o establece un valor. Los miembros con forma de expresión proporcionan una sintaxis simplificada para admitir este escenario. A partir de C# 6, un indizador de solo lectura puede implementarse como un miembro con forma de expresión, como se muestra en el ejemplo siguiente.
using System; class SampleCollection { // Declare an array to store the data elements. private T[] arr = new T[100]; int nextIndex = 0; // Define the indexer to allow client code to use [] notation. public T this[int i] => arr[i]; public void Add(T value) { if (nextIndex >= arr.Length) throw new IndexOutOfRangeException($"The collection can hold only {arr.Length} elements."); arr[nextIndex++] = value; } } class Program { static void Main() { var stringCollection = new SampleCollection(); stringCollection.Add("Hello, World"); System.Console.WriteLine(stringCollection[0]); } } // The example displays the following output: // Hello, World.
Tenga en cuenta que
=>
presenta el cuerpo de la expresión y que la palabra clave
get
no se utiliza.
A partir de C# 7, los descriptores de acceso get y set se pueden implementar como miembros con forma de expresión. En este caso, sí deben utilizarse las palabras clave get y set . Por ejemplo: using System; class SampleCollection { // Declare an array to store the data elements. private T[] arr = new T[100]; // Define the indexer to allow client code to use [] notation. public T this[int i] { get => arr[i]; set => arr[i] = value; } } class Program { static void Main() { var stringCollection = new SampleCollection(); stringCollection[0] = "Hello, World."; Console.WriteLine(stringCollection[0]); } } // The example displays the following output: // Hello, World.
Información general sobre los indizadores Los indizadores permiten indizar objetos de manera similar a como se hace con las matrices. Un descriptor de acceso
get
devuelve un valor. Un descriptor de acceso
set
asigna un valor.
La palabra clave this se usa para definir los indizadores. La palabra clave value se usa para definir el valor asignado por el indizador
set
.
Los indizadores no tienen que ser indizados por un valor entero; depende de usted cómo definir el mecanismo de búsqueda concreto. Los indizadores se pueden sobrecargar. Los indizadores pueden tener más de un parámetro formal, por ejemplo, al tener acceso a una matriz bidimensional.
Secciones relacionadas Utilizar indizadores Indizadores en Interfaces Comparación entre propiedades e indizadores Restringir la accesibilidad del descriptor de acceso
Especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Vea también Guía de programación de C# Propiedades
Interfaces (Guía de programación de C#) 03/10/2017 • 4 min to read • Edit Online
Una interfaz contiene las definiciones de un grupo de funcionalidades relacionadas que una clase o una estructura pueden implementar. Mediante las interfaces puede incluir, por ejemplo, un comportamiento de varios orígenes en una clase. Esta capacidad es importante en C# porque el lenguaje no admite la herencia múltiple de clases. Además, debe usar una interfaz si desea simular la herencia de estructuras, porque no pueden heredar de otra estructura o clase. Defina una interfaz mediante la palabra clave interface, como se muestra en el ejemplo siguiente. interface IEquatable { bool Equals(T obj); }
Cualquier clase o estructura que implementa la interfaz IEquatable debe contener una definición para un método Equals que coincida con la firma que la interfaz especifica. Como resultado, puede contar con una clase que implementa IEquatable para contener un método Equals con el que una instancia de la clase puede determinar si es igual a otra instancia de la misma clase. La definición de IEquatable no proporciona una implementación para Equals . La interfaz define solo la firma. De esa manera, una interfaz en C# es similar a una clase abstracta en la que todos los métodos son abstractos. Sin embargo, una clase o estructura puede implementar varias interfaces, pero una clase solo puede heredar una clase única, ya sea abstracta o no. Por tanto, mediante las interfaces, puede incluir un comportamiento de varios orígenes en una clase. Para obtener más información sobre las clases abstractas, vea Clases y miembros de clase abstractos y sellados . Las interfaces pueden contener métodos, propiedades, eventos, indizadores o cualquier combinación de estos cuatro tipos de miembros. Para obtener vínculos a ejemplos, vea Secciones relacionadas. Una interfaz no puede contener constantes, campos, operadores, constructores de instancias, finalizadores ni tipos. Los miembros de interfaz son públicos automáticamente y no pueden incluir modificadores de acceso. Los miembros tampoco pueden ser estáticos. Para implementar un miembro de interfaz, el miembro correspondiente de la clase de implementación debe ser público, no estático y tener el mismo nombre y firma que el miembro de interfaz. Cuando una clase o estructura implementa una interfaz, la clase o estructura debe proporcionar una implementación para todos los miembros que define la interfaz. La propia interfaz no proporciona ninguna funcionalidad que una clase o estructura puedan heredar de la misma la forma en que pueden heredar la funcionalidad de la clase base. Sin embargo, si una clase base implementa una interfaz, cualquier clase que se derive de la clase base hereda esta implementación. En el ejemplo siguiente se muestra una implementación de la interfaz IEquatable. La clase de implementación debe proporcionar una implementación del método Equals.
Car
public class Car : IEquatable { public string Make {get; set;} public string Model { get; set; } public string Year { get; set; } // Implementation of IEquatable interface public bool Equals(Car car) { if (this.Make == car.Make && this.Model == car.Model && this.Year == car.Year) { return true; } else return false; } }
Las propiedades y los indizadores de una clase pueden definir descriptores de acceso adicionales para una propiedad o indizador que estén definidos en una interfaz. Por ejemplo, una interfaz puede declarar una propiedad que tenga un descriptor de acceso get. La clase que implementa la interfaz puede declarar la misma propiedad con un descriptor de acceso get y set. Sin embargo, si la propiedad o el indizador usan una implementación explícita, los descriptores de acceso deben coincidir. Para obtener más información sobre la implementación explícita, vea Implementación de interfaz explícita y Propiedades de interfaces. Las interfaces pueden implementar otras interfaces. Una clase puede incluir una interfaz varias veces a través de las clases base que hereda o a través de las interfaces que otras interfaces implementan. Sin embargo, la clase puede proporcionar una implementación de una interfaz solo una vez y solo si la clase declara la interfaz como parte de la definición de la clase ( class ClassName : InterfaceName ). Si la interfaz se hereda porque se heredó una clase base que implementa la interfaz, la clase base proporciona la implementación de los miembros de la interfaz. Sin embargo, la clase derivada puede volver a implementar los miembros de interfaz, en lugar de usar la implementación heredada. Una clase base también puede implementar miembros de interfaz mediante el uso de los miembros virtuales. En ese caso, una clase derivada puede cambiar el comportamiento de la interfaz reemplazando los miembros virtuales. Para obtener más información sobre los miembros virtuales, vea Polimorfismo.
Resumen de interfaces Una interfaz tiene las propiedades siguientes: Una interfaz es como una clase base abstracta. Cualquier clase o estructura que implementa la interfaz debe implementar todos sus miembros. No se puede crear una instancia de una interfaz directamente. Sus miembros se implementan por medio de cualquier clase o estructura que implementa la interfaz. Las interfaces pueden contener eventos, indizadores, métodos y propiedades. Las interfaces no contienen ninguna implementación de métodos. Una clase o estructura puede implementar varias interfaces. Una clase puede heredar una clase base y también implementar una o varias interfaces.
En esta sección Implementación de interfaz explícita
Explica cómo crear un miembro de clase que es específico de una interfaz. Cómo: Implementar explícitamente miembros de interfaz Proporciona un ejemplo de cómo implementar explícitamente miembros de interfaces. Cómo: Implementar explícitamente miembros de dos interfaces Proporciona un ejemplo de cómo implementar explícitamente miembros de interfaces con herencia.
Secciones relacionadas Propiedades de interfaz Indizadores en Interfaces Cómo: Implementar eventos de interfaz Clases y structs Herencia Métodos Polimorfismo Clases y miembros de clase abstractos y sellados Propiedades Eventos Indizadores
Capítulo destacado del libro Interfaces (Interfaces) en Learning C# 3.0: Master the Fundamentals of C# 3.0 (Aprendizaje de C# 3.0: Dominar los conceptos fundamentales de C# 3.0)
Vea también Guía de programación de C# Herencia
Interoperabilidad (Guía de programación de C#) 03/10/2017 • 1 min to read • Edit Online
La interoperabilidad permite conservar y aprovechar las inversiones existentes en código no administrado. El código que se ejecuta bajo el control de Common Language Runtime (CLR) se denomina código administrado, y el código que se ejecuta fuera de CLR se denomina código no administrado. COM, COM+, los componentes de C++, los componentes de ActiveX y la API Win32 de Microsoft son ejemplos de código no administrado. .NET Framework habilita la interoperabilidad con código no administrado a través de los servicios de invocación de plataforma, el espacio de nombres System.Runtime.InteropServices, la interoperabilidad de C++ y la interoperabilidad COM.
En esta sección Información general sobre interoperabilidad Se describen métodos para habilitar la interoperabilidad entre el código administrado y el código no administrado de C#. Cómo: Tener acceso a objetos de interoperabilidad de Office mediante las características de Visual C# Describe las características introducidas en Visual C# para facilitar la programación de Office. Cómo: Utilizar propiedades indizadas en la programación de interoperabilidad COM Se describe cómo utilizar las propiedades indizadas para acceder a las propiedades de COM que tienen parámetros. Cómo: Utilizar la invocación de plataforma para reproducir un archivo de sonido Se describe cómo usar los servicios de invocación de plataforma para reproducir un archivo de sonido .wav en el sistema operativo Windows. Tutorial: Programación de Office Muestra cómo crear un libro de Excel y un documento de Word que contiene un vínculo al libro. Clase COM de ejemplo Muestra cómo exponer una clase de C# como un objeto COM.
Especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Vea también Marshal.ReleaseComObject Guía de programación de C# Interoperating with Unmanaged Code (Interoperabilidad con código no administrado) Tutorial: Programación de Office
Main() y argumentos de la línea de comandos (Guía de programación de C#) 03/10/2017 • 2 min to read • Edit Online
El método Main es el punto de entrada de una aplicación de C# (las bibliotecas y los servicios no requieren un método Main como punto de entrada). Cuando se inicia la aplicación, el método Main es el primero que se invoca. Solo puede haber un punto de entrada en un programa de C#. Si hay más de una clase que tiene un método Main , debe compilar el programa con la opción del compilador /main para especificar qué método Main desea utilizar como punto de entrada. Para obtener más información, consulte /main (Opciones del compilador de C#). 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 de un programa ejecutable; es donde se inicia y finaliza el control del programa. Main se declara dentro de una clase o estructura. El valor de Main debe ser estático y no público. (En el ejemplo anterior, recibe el acceso predeterminado de privado). La clase o estructura envolvente no debe ser estático. Main puede tener un tipo de valor devuelto void , int o, a partir de C# 7.1, Task o Task . Solo si Main devuelve un tipo de valor devuelto Task o Task , la declaración de Main puede incluir el modificador async , pero tenga en cuenta que se excluirá de forma específica un método async void Main . El método Main se puede declarar con o sin un parámetro string[] que contiene los argumentos de línea de comandos. Al usar Visual Studio para crear aplicaciones Windows, se puede agregar el parámetro manualmente o utilizar la clase Environment con el fin de obtener los argumentos de la línea de comandos. Los parámetros se leen como argumentos de línea de comandos indizados con cero. A diferencia de C y C++, el nombre del programa no se trata como el primer argumento de línea de comandos. Al agregar los tipos de valor devuelto async , Task y Task , se simplifica el código de programa cuando las aplicaciones de consola tienen que realizar tareas de inicio y await de operaciones asincrónicas en Main .
especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Vea también Compilar la línea de comandos con csc.exe Guía de programación de C# Métodos Dentro de un programa de C#
Espacios de nombres (Guía de programación de C#) 03/10/2017 • 1 min to read • Edit Online
Los espacios de nombres se usan mucho en programación de C# de dos maneras. En primer lugar, .NET Framework usa espacios de nombres para organizar sus clases, de la siguiente manera: System.Console.WriteLine("Hello World!");
es un espacio de nombres y Console es una clase de ese espacio de nombres. La palabra clave puede usar para que no se necesite el nombre completo, como en el ejemplo siguiente: System
using
se
using System;
Console.WriteLine("Hello"); Console.WriteLine("World!");
Para obtener más información, consulte using (Directiva). En segundo lugar, declarar sus propios espacios de nombres puede ayudarle a controlar el ámbito de nombres de clase y método en proyectos de programación grandes. Use la palabra clave namespace para declarar un espacio de nombres, como en el ejemplo siguiente: namespace SampleNamespace { class SampleClass { public void SampleMethod() { System.Console.WriteLine( "SampleMethod inside SampleNamespace"); } } }
Información general sobre los espacios de nombres Los espacios de nombres tienen las propiedades siguientes: Organizan proyectos de código de gran tamaño. Se delimitan mediante el operador using directive
.
.
obvia la necesidad de especificar el nombre del espacio de nombres para cada clase.
El espacio de nombres global es el espacio de nombres "raíz": espacio de nombres System de .NET Framework.
global::System
siempre hará referencia al
Secciones relacionadas Vea los siguientes temas para obtener más información sobre los espacios de nombres:
Utilizar espacios de nombres Cómo: Utilizar el alias del espacio de nombres global Cómo: Utilizar el espacio de nombres My
Especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Vea también Guía de programación de C# Palabras clave del espacio de nombres using Directive (using [Directiva, Referencia de C#]) Operador :: .!
Tipos que aceptan valores NULL (Guía de programación de C#) 03/10/2017 • 3 min to read • Edit Online
Los tipos que aceptan valores NULL son instancias de la estructura Nullable. Un tipo que acepta valores NULL puede representar el intervalo de valores correcto para su tipo de valor subyacente, además de un valor null adicional correcto. Por ejemplo, a un valor Nullable , también conocido como "Nullable of Int32", se le puede asignar cualquier valor comprendido entre -2147483648 y 2147483647, o se le puede asignar el valor null . A Nullable se le pueden asignar los valores true, false o null. La capacidad de asignar null a tipos numéricos y booleanos resulta especialmente útil cuando se trabaja con bases de datos y otros tipos de datos que contienen elementos a los que no se les puede asignar ningún valor. Por ejemplo, un campo booleano en una base de datos puede almacenar los valores true o false , o puede ser indefinido. using System; class NullableExample { static void Main() { int? num = null; // Is the HasValue property true? if (num.HasValue) { Console.WriteLine("num = " + num.Value); } else { Console.WriteLine("num = Null"); } // y is set to zero int y = num.GetValueOrDefault(); // num.Value throws an InvalidOperationException if num.HasValue is false try { y = num.Value; } catch (InvalidOperationException e) { Console.WriteLine(e.Message); } } } // The example displays the following output: // num = Null // Nullable object must have a value.
Para obtener más ejemplos, vea Utilizar tipos que aceptan valores NULL.
Información general sobre tipos que aceptan valores NULL Los tipos que aceptan valores NULL tienen la siguientes características: Los tipos que aceptan valores NULL representan variables de tipo de valor a las que se puede asignar el
valor null . No se puede crear un tipo que acepta valores NULL basado en un tipo de referencia. (Los tipos de referencia ya admiten el valor null ). La sintaxis T? es una abreviatura de Nullable, donde intercambiables.
T
es un tipo de valor. Las dos formas son
Asigne un valor a un tipo que acepta valores NULL tal como lo haría para un tipo de valor normal, por ejemplo int? x = 10; o double? d = 4.108 . A un tipo que acepta valores NULL también se le puede asignar el valor null : int? x = null. . Use el método Nullable.GetValueOrDefault para devolver el valor asignado, o bien el valor predeterminado para el tipo subyacente si el valor es null , por ejemplo, int j = x.GetValueOrDefault(); . Use las propiedades de solo lectura HasValue y Value para probar si hay valores NULL y recuperar el valor, como se muestra en el ejemplo siguiente: if(x.HasValue) j = x.Value; La propiedad
HasValue
devuelve
true
si la variable contiene un valor, o
false
si es
null
.
La propiedad Value devuelve un valor si se asigna uno. De lo contrario, se produce una excepción InvalidOperationException. El valor predeterminado de predeterminado.
HasValue
es
false
. La propiedad
Value
no tiene ningún valor
También puede utilizar los operadores == y != con un tipo que acepta valores NULL, como se muestra en el ejemplo siguiente: if (x != null) y = x; Utilice el operador ?? para asignar un valor predeterminado que se aplicará cuando un tipo que acepta valores NULL cuyo valor actual es null se asigna a un tipo que no acepta valores NULL, por ejemplo int? x = null; int y = x ?? -1;
No se permiten los tipos anidados que aceptan valores NULL. La línea siguiente no se compilará: Nullable> n;
Secciones relacionadas Para obtener más información: Utilizar tipos que aceptan valores NULL Aplicar la conversión boxing a tipos que aceptan valores NULL Operador ??
Especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Vea también Nullable Guía de programación de C# C# Referencia de C# ¿Qué significa exactamente "elevado"?
Conceptos de programación (C#) 03/10/2017 • 1 min to read • Edit Online
En esta sección se explican los conceptos de programación del lenguaje C#.
En esta sección TÍTULO
DESCRIPCIÓN
Ensamblados y caché global de ensamblados (C#)
Describe cómo crear y utilizar ensamblados.
Programación asincrónica con Async y Await (C#)
Describe cómo escribir soluciones asincrónicas mediante las palabras clave Async y Await en C#. Incluye un tutorial.
Atributos (C#)
Describe cómo proporcionar información adicional sobre elementos de programación como tipos, campos, métodos y propiedades mediante el uso de atributos.
Información del llamador (C#)
Describe cómo obtener información sobre el llamador de un método. Esta información incluye la ruta de acceso al código fuente y el número de línea de dicho código y el nombre de miembro del llamador.
Colecciones (C#)
Describe algunos de los tipos de colecciones proporcionadas por .NET Framework. Muestra cómo usar colecciones sencillas y colecciones de pares clave-valor.
Covarianza y contravarianza (C#)
Describe cómo habilitar la conversión implícita de parámetros de tipo genérico en interfaces y delegados.
Árboles de expresión (C#)
Explica cómo puede utilizar árboles de expresión para habilitar la modificación dinámica de código ejecutable.
Iteradores (C#)
Describe los iteradores, que se usan para recorrer colecciones y devolver los elementos uno a uno.
Language Integrated Query (LINQ) (C#)
Se describen las eficaces funciones de consulta de la sintaxis del lenguaje C#, así como el modelo para consultar bases de datos relacionales, documentos XML, conjuntos de datos y colecciones en memoria.
Programación orientada a objetos (C#)
Describe conceptos comunes orientados a objetos, incluidos la encapsulación, la herencia y el polimorfismo.
Reflexión (C#)
Se explica cómo usar la reflexión para crear dinámicamente una instancia de un tipo, enlazar el tipo a un objeto existente u obtener el tipo desde un objeto existente e invocar sus métodos, o acceder a sus campos y propiedades.
Serialización (C#)
Describe los conceptos clave de la serialización binaria, XML y SOAP.
TÍTULO
DESCRIPCIÓN
Subprocesamiento (C#)
Proporciona información general sobre el modelo de subprocesos .NET y muestra cómo escribir código que realiza varias tareas al mismo tiempo para mejorar el rendimiento y la capacidad de respuesta de las aplicaciones.
Secciones relacionadas Sugerencias para mejorar el rendimiento
Se describen varias reglas básicas que pueden ayudarle a aumentar el rendimiento de la aplicación.
Instrucciones, expresiones y operadores (Guía de programación de C#) 03/10/2017 • 1 min to read • Edit Online
El código de C# que conforma una aplicación consta de instrucciones basadas en palabras clave, expresiones y operadores. Esta sección contiene información sobre los elementos fundamentales de un programa de C#. Para obtener más información, consulte: Instrucciones Expresiones Miembros con forma de expresión Operadores Funciones anónimas Operadores sobrecargables Operadores de conversión Utilizar operadores de conversión Cómo: Implementar conversiones definidas por el usuario entre structs Cómo: Utilizar la sobrecarga de operadores para crear una clase de números complejos Comparaciones de igualdad
Especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Vea también Guía de programación de C# Conversiones de tipos
Cadenas (Guía de programación de C#) 03/10/2017 • 12 min to read • Edit Online
Una cadena es un objeto de tipo String cuyo valor es texto. Internamente, el texto se almacena como una colección secuencial de solo lectura de objetos Char. No hay ningún carácter que finaliza en null al final de una cadena de C#; por lo tanto, la cadena de C# puede contener cualquier número de caracteres nulos insertados ('\0'). La propiedad Length de una cadena representa el número de objetos Char que contiene, no el número de caracteres Unicode. Para obtener acceso a los puntos de código Unicode individuales de una cadena, use el objeto StringInfo.
cadena frente System.String En C#, la palabra clave string es un alias de String. Por lo tanto, String y string son equivalentes y se puede utilizar la convención de nomenclatura que prefiera. La clase String proporciona muchos métodos para crear, manipular y comparar cadenas de forma segura. Además, el lenguaje C# sobrecarga algunos operadores para simplificar las operaciones de cadena comunes. Para más información sobre la palabra clave, consulte string. Para obtener más información sobre el tipo y sus métodos, vea String.
Declaración e inicialización de cadenas Puede declarar e inicializar cadenas de varias maneras, tal como se muestra en el ejemplo siguiente: // Declare without initializing. string message1; // Initialize to null. string message2 = null; // Initialize as an empty string. // Use the Empty constant instead of the literal "". string message3 = System.String.Empty; //Initialize with a regular string literal. string oldPath = "c:\\Program Files\\Microsoft Visual Studio 8.0"; // Initialize with a verbatim string literal. string newPath = @"c:\Program Files\Microsoft Visual Studio 9.0"; // Use System.String if you prefer. System.String greeting = "Hello World!"; // In local variables (i.e. within a method body) // you can use implicit typing. var temp = "I'm still a strongly-typed System.String!"; // Use a const string to prevent 'message4' from // being used to store another string value. const string message4 = "You can't get rid of me!"; // Use the String constructor only when creating // a string from a char*, char[], or sbyte*. See // System.String documentation for details. char[] letters = { 'A', 'B', 'C' }; string alphabet = new string(letters);
Tenga en cuenta que no se usa el operador new para crear un objeto de cadena, salvo cuando se inicialice la cadena con una matriz de caracteres.
Inicialice una cadena con el valor constante Empty para crear un objeto String cuya cadena tenga longitud cero. La representación literal de la cadena de una cadena de longitud cero es "". Mediante la inicialización de las cadenas con el valor Empty en lugar de null, puede reducir las posibilidades de que se produzca una excepción NullReferenceException. Use el método estático IsNullOrEmpty(String) para comprobar el valor de una cadena antes de intentar obtener acceso a ella.
Inmutabilidad de los objetos de cadena Los objetos de cadena son inmutables: no se pueden cambiar después de haberse creado. Todos los métodos String y operadores de C# que parecen modificar una cadena en realidad devuelven los resultados en un nuevo objeto de cadena. En el siguiente ejemplo, cuando el contenido de s1 y s2 se concatena para formar una sola cadena, las dos cadenas originales no se modifican. El operador += crea una nueva cadena que contiene el contenido combinado. Este nuevo objeto se asigna a la variable s1 y el objeto original que se asignó a s1 se libera para la recolección de elementos no utilizados porque ninguna otra variable contiene una referencia a él. string s1 = "A string is more "; string s2 = "than the sum of its chars."; // // // s1
Concatenate s1 and s2. This actually creates a new string object and stores it in s1, releasing the reference to the original object. += s2;
System.Console.WriteLine(s1); // Output: A string is more than the sum of its chars.
Dado que una "modificación" de cadena es en realidad una creación de cadena, debe tener cuidado al crear referencias a las cadenas. Si crea una referencia a una cadena y después "modifica" la cadena original, la referencia seguirá apuntando al objeto original en lugar de al objeto nuevo creado al modificarse la cadena. El código siguiente muestra este comportamiento: string s1 = "Hello "; string s2 = s1; s1 += "World"; System.Console.WriteLine(s2); //Output: Hello
Para más información acerca de cómo crear cadenas nuevas basadas en modificaciones como las operaciones de buscar y reemplazar en la cadena original, consulte Cómo: Modificar el contenido de cadenas.
Literales de cadena regulares y textuales Utilice literales de cadena regulares cuando tenga que insertar caracteres de escape proporcionados por C#, tal como se muestra en el ejemplo siguiente:
string columns = "Column 1\tColumn 2\tColumn 3"; //Output: Column 1 Column 2 Column 3 string rows = "Row 1\r\nRow 2\r\nRow 3"; /* Output: Row 1 Row 2 Row 3 */ string title = "\"The \u00C6olean Harp\", by Samuel Taylor Coleridge"; //Output: "The Æolean Harp", by Samuel Taylor Coleridge
Utilice cadenas textuales para mayor comodidad y mejor legibilidad cuando el texto de la cadena contenga caracteres de barra diagonal inversa, por ejemplo, en rutas de acceso de archivo. Como las cadenas textuales conservan los caracteres de nueva línea como parte del texto de la cadena, pueden utilizarse para inicializar cadenas multilíneas. Utilice comillas dobles para insertar una comilla simple dentro de una cadena textual. En el ejemplo siguiente se muestran algunos usos habituales de las cadenas textuales: string filePath = @"C:\Users\scoleridge\Documents\"; //Output: C:\Users\scoleridge\Documents\ string text = @"My pensive SARA ! thy soft cheek reclined Thus on mine arm, most soothing sweet it is To sit beside our Cot,..."; /* Output: My pensive SARA ! thy soft cheek reclined Thus on mine arm, most soothing sweet it is To sit beside our Cot,... */ string quote = @"Her name was ""Sara."""; //Output: Her name was "Sara."
Secuencias de escape de cadena SECUENCIA DE ESCAPE
NOMBRE DE CARÁCTER
CODIFICACIÓN UNICODE
\'
Comilla simple
0x0027
\"
Comilla doble
0x0022
\\
Barra diagonal inversa
0x005C
\0
Null
0x0000
\a
Alerta
0x0007
\b
Retroceso
0x0008
\f
Avance de página
0x000C
\n
Nueva línea
0x000A
\r
Retorno de carro
0x000D
SECUENCIA DE ESCAPE
NOMBRE DE CARÁCTER
CODIFICACIÓN UNICODE
\t
Tabulación horizontal
0x0009
\U
Secuencia de escape Unicode para pares suplentes.
\Unnnnnnnn
\u
Secuencia de escape Unicode
\u0041 = "A"
\v
Tabulación vertical
0x000B
\x
Secuencia de escape Unicode similar a "\u" excepto con longitud variable.
\x0041 = "A"
NOTA En tiempo de compilación, las cadenas textuales se convierten en cadenas normales con las mismas secuencias de escape. Por lo tanto, si se muestra una cadena textual en la ventana Inspección del depurador, verá los caracteres de escape agregados por el compilador, no la versión textual del código fuente. Por ejemplo, la cadena textual @"C:\files.txt" aparecerá en la ventana Inspección, como "C:\\files.txt".
Cadenas de formato Una cadena de formato es una cadena cuyo contenido puede determinarse de manera dinámica en tiempo de ejecución. Puede crear una cadena de formato mediante el método estático Format e insertar los marcadores de posición entre llaves que se reemplazarán por otros valores en tiempo de ejecución. En el ejemplo siguiente se utiliza una cadena de formato para generar el resultado de cada iteración de un bucle: class FormatString { static void Main() { // Get user input. System.Console.WriteLine("Enter a number"); string input = System.Console.ReadLine(); // Convert the input string to an int. int j; System.Int32.TryParse(input, out j); // Write a different string each iteration. string s; for (int i = 0; i < 10; i++) { // A simple format string with no alignment formatting. s = System.String.Format("{0} times {1} = {2}", i, j, (i * j)); System.Console.WriteLine(s); } //Keep the console window open in debug mode. System.Console.ReadKey(); } }
Una sobrecarga del método WriteLine toma una cadena de formato como un parámetro. Por lo tanto, solo se puede insertar un literal de cadena de formato sin una llamada explícita al método. Pero si usa el método WriteLine para mostrar la salida de la depuración en la ventana Salida de Visual Studio, debe llamar explícitamente al
método Format porque WriteLine solo acepta una cadena, no una cadena de formato. Para más información sobre las cadenas de formato, consulte Formatting Types (Tipos de formato).
Subcadenas Una subcadena es cualquier secuencia de caracteres que se encuentra en una cadena. Use el método Substring para crear una nueva cadena de una parte de la cadena original. Puede buscar una o más apariciones de una subcadena con el método IndexOf. Use el método Replace para reemplazar todas las apariciones de una subcadena especificada por una nueva cadena. Al igual que el método Substring, Replace devuelve una cadena nueva y no modifica la cadena original. Para más información, consulte Cómo: Buscar cadenas mediante los métodos String y Cómo: Modificar el contenido de cadenas. string s3 = "Visual C# Express"; System.Console.WriteLine(s3.Substring(7, 2)); // Output: "C#" System.Console.WriteLine(s3.Replace("C#", "Basic")); // Output: "Visual Basic Express" // Index values are zero-based int index = s3.IndexOf("C"); // index = 7
Acceso a caracteres individuales Puede utilizar la notación de matriz con un valor de índice para adquirir acceso de solo lectura a caracteres individuales, como en el ejemplo siguiente: string s5 = "Printing backwards"; for (int i = 0; i < s5.Length; i++) { System.Console.Write(s5[s5.Length - i - 1]); } // Output: "sdrawkcab gnitnirP"
Si el método String no proporciona la funcionalidad que debe tener para modificar los caracteres individuales de una cadena, puede usar un objeto StringBuilder para modificar los caracteres individuales "en contexto" y, después, crear una cadena para almacenar los resultados mediante el método StringBuilder. En el ejemplo siguiente, se supone que debe modificar la cadena original de una manera determinada y, después, almacenar los resultados para un uso futuro: string question = "hOW DOES mICROSOFT wORD DEAL WITH THE cAPS lOCK KEY?"; System.Text.StringBuilder sb = new System.Text.StringBuilder(question); for (int j = 0; j < sb.Length; j++) { if (System.Char.IsLower(sb[j]) == true) sb[j] = System.Char.ToUpper(sb[j]); else if (System.Char.IsUpper(sb[j]) == true) sb[j] = System.Char.ToLower(sb[j]); } // Store the new string. string corrected = sb.ToString(); System.Console.WriteLine(corrected); // Output: How does Microsoft Word deal with the Caps Lock key?
Cadenas nulas y cadenas vacías Una cadena vacía es una instancia de un objeto System.String que contiene cero caracteres. Las cadenas vacías se utilizan a menudo en distintos escenarios de programación para representar un campo de texto en blanco. Puede llamar a métodos en cadenas vacías porque son objetos System.String válidos. Las cadenas vacías se inicializan como sigue: string s = String.Empty;
En cambio, una cadena nula no hace referencia a una instancia de un objeto System.String y cualquier intento de llamar a un método en una cadena nula produce una excepción NullReferenceException. Sin embargo, puede utilizar cadenas nulas en operaciones de comparación y concatenación con otras cadenas. Los ejemplos siguientes muestran algunos casos en que una referencia a una cadena nula provoca y no provoca una excepción: static void Main() { string str = "hello"; string nullStr = null; string emptyStr = String.Empty; string tempStr = str + nullStr; // Output of the following line: hello Console.WriteLine(tempStr); bool b = (emptyStr == nullStr); // Output of the following line: False Console.WriteLine(b); // The following line creates a new empty string. string newStr = emptyStr + nullStr; // Null strings and empty strings behave differently. The following // two lines display 0. Console.WriteLine(emptyStr.Length); Console.WriteLine(newStr.Length); // The following line raises a NullReferenceException. //Console.WriteLine(nullStr.Length); // The null character can be displayed and counted, like other chars. string s1 = "\x0" + "abc"; string s2 = "abc" + "\x0"; // Output of the following line: * abc* Console.WriteLine("*" + s1 + "*"); // Output of the following line: *abc * Console.WriteLine("*" + s2 + "*"); // Output of the following line: 4 Console.WriteLine(s2.Length); }
Uso de StringBuilder para la creación rápida de cadenas Las operaciones de cadena en .NET están muy optimizadas y en la mayoría de los casos no afectan significativamente al rendimiento. Sin embargo, en algunos escenarios, como los bucles de pequeñas dimensiones que se ejecutan cientos o miles de veces, las operaciones de cadena pueden afectar al rendimiento. La clase StringBuilder crea un búfer de cadena que proporciona un mejor rendimiento si el programa realiza muchas manipulaciones de cadenas. La cadena StringBuilder también permite reasignar 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:
System.Text.StringBuilder sb = new System.Text.StringBuilder("Rat: the ideal pet"); sb[0] = 'C'; System.Console.WriteLine(sb.ToString()); System.Console.ReadLine(); //Outputs Cat: the ideal pet
En este ejemplo, se usa 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 } }
Cadenas, métodos de extensión y LINQ Dado que el tipo String implementa IEnumerable, puede usar los métodos de extensión definidos en la clase Enumerable en cadenas. Para evitar el desorden visual, estos métodos se excluyen de IntelliSense para el tipo String, pero aun así están disponibles. También puede utilizar expresiones de consulta LINQ en cadenas. Para más información, consulte LINQ and Strings (LINQ y cadenas).
Temas relacionados TEMA
DESCRIPCIÓN
Cómo: Modificar el contenido de cadenas
Proporciona un ejemplo de código que muestra cómo modificar el contenido de cadenas.
Cómo: Concatenar varias cadenas
Muestra cómo utilizar el operador + y la clase Stringbuilder para unir cadenas en tiempo de compilación y de ejecución.
Cómo: Comparar cadenas
Muestra cómo realizar comparaciones ordinales de las cadenas.
Cómo: Analizar cadenas mediante String.Split
Contiene un ejemplo de código que muestra cómo utilizar el método String.Split para analizar cadenas.
Cómo: Buscar cadenas mediante los métodos String
Explica cómo utilizar métodos específicos para buscar cadenas.
TEMA
DESCRIPCIÓN
Cómo: Buscar cadenas mediante expresiones regulares
Explica cómo utilizar expresiones regulares para buscar cadenas.
Cómo: Determinar si una cadena representa un valor numérico
Muestra cómo analizar de forma segura una cadena para ver si tiene un valor numérico válido.
Cómo: Convertir una cadena en un valor DateTime
Muestra cómo convertir una cadena como "24/01/2008" en un objeto System.DateTime.
Operaciones básicas de cadenas
Proporciona vínculos a temas que usan los métodos System.String y System.Text.StringBuilder para realizar operaciones básicas de cadenas.
Analizar cadenas
Describe cómo insertar caracteres o espacios vacíos en una cadena.
Comparar cadenas
Incluye información sobre cómo comparar cadenas y proporciona ejemplos de C# y Visual Basic.
Utilizar la clase StringBuilder
Describe cómo crear y modificar objetos de cadena dinámicos con la clase StringBuilder.
LINQ y cadenas
Proporciona información sobre cómo realizar varias operaciones de cadena utilizando consultas LINQ.
Guía de programación de C#
Proporciona vínculos a temas que explican las construcciones de programación en C#.
Tipos (Guía de programación de C#) 03/10/2017 • 12 min to read • Edit Online
Tipos, variables y valores C# es un lenguaje fuertemente tipado. Todas las variables y constantes tienen un tipo, al igual que todas las expresiones que se evalúan como un valor. Cada una de las firmas de método especifica un tipo para cada parámetro de entrada y para el valor devuelto. La biblioteca de clases .NET Framework define un conjunto de tipos numéricos integrados, así como tipos más complejos que representan una amplia variedad de construcciones lógicas, como el sistema de archivos, conexiones de red, colecciones y matrices de objetos, y fechas. Los programas de C# típicos usan tipos de la biblioteca de clases, así como tipos definidos por el usuario que modelan los conceptos que son específicos del dominio del problema del programa. Entre la información almacenada en un tipo se puede incluir lo siguiente: El espacio de almacenamiento que requiere una variable del tipo. Los valores máximo y mínimo que puede representar. Los miembros (métodos, campos, eventos, etc.) que contiene. El tipo base del que hereda. La ubicación donde se asignará la memoria para variables en tiempo de ejecución. Los tipos de operaciones permitidas. El compilador usa información de tipo para garantizar que todas las operaciones que se realizan en el código cuentan con seguridad de tipos. Por ejemplo, si declara una variable de tipo int, el compilador le permite usar la variable en operaciones de suma y resta. Si intenta realizar esas mismas operaciones en una variable de tipo bool, el compilador genera un error, como se muestra en el siguiente ejemplo: int a = 5; int b = a + 2; //OK bool test = true; // Error. Operator '+' cannot be applied to operands of type 'int' and 'bool'. int c = a + test;
NOTA Los desarrolladores de C y C++ deben tener en cuenta que, en C#, bool no se puede convertir en int.
El compilador inserta la información de tipo en el archivo ejecutable como metadatos. Common Language Runtime (CLR) utiliza esos metadatos en tiempo de ejecución para garantizar aún más la seguridad de tipos cuando asigna y reclama memoria. Definición de tipos en declaraciones de variable Cuando declare una variable o constante en un programa, debe especificar su tipo o utilizar la palabra clave var para que el compilador infiera el tipo. En el ejemplo siguiente se muestran algunas declaraciones de variable que utilizan tanto tipos numéricos integrados como tipos complejos definidos por el usuario:
// Declaration only: float temperature; string name; MyClass myClass; // Declaration with initializers (four examples): char firstLetter = 'C'; var limit = 3; int[] source = { 0, 1, 2, 3, 4, 5 }; var query = from item in source where item <= limit select item;
Los tipos de parámetros de método y valores devueltos se especifican en la firma del método. En la siguiente firma se muestra un método que requiere una variable int como argumento de entrada y devuelve una cadena: public string GetName(int ID) { if (ID < names.Length) return names[ID]; else return String.Empty; } private string[] names = { "Spencer", "Sally", "Doug" };
Tras declarar una variable, no se puede volver a declarar con un nuevo tipo y no se le puede asignar un valor que no sea compatible con su tipo declarado. Por ejemplo, no puede declarar un valor int y, luego, asignarle un valor booleano de true. En cambio, los valores se pueden convertir en otros tipos, por ejemplo, cuando se asignan a variables nuevas o se pasan como argumentos de método. El compilador realiza automáticamente una conversión de tipo que no da lugar a una pérdida de datos. Una conversión que pueda dar lugar a la pérdida de datos requiere un valor cast en el código fuente. Para más información, vea Conversiones de tipos.
Tipos integrados C# proporciona un conjunto estándar de tipos numéricos integrados para representar números enteros, valores de punto flotante, expresiones booleanas, caracteres de texto, valores decimales y otros tipos de datos. También hay tipos string y object integrados. Están disponibles para su uso en cualquier programa de C#. Para obtener más información sobre los tipos integrados, vea Tablas de referencia para tipos.
Tipos personalizados Las construcciones struct, class, interface y enum se utilizan para crear sus propios tipos personalizados. La biblioteca de clases .NET Framework es en sí misma una colección de tipos personalizados proporcionados por Microsoft que puede usar en sus propias aplicaciones. De forma predeterminada, los tipos usados con más frecuencia en la biblioteca de clases están disponibles en cualquier programa de C#. Otros están disponibles solo cuando agrega explícitamente una referencia de proyecto al ensamblado en el que se definen. Una vez que el compilador tenga una referencia al ensamblado, puede declarar variables (y constantes) de los tipos declarados en dicho ensamblado en el código fuente. Para más información, vea Biblioteca de clases .NET Framework.
Common Type System Es importante entender dos aspectos fundamentales sobre el sistema de tipos en .NET Framework: Es compatible con el principio de herencia. Los tipos pueden derivarse de otros tipos, denominados tipos
base. El tipo derivado hereda (con algunas restricciones), los métodos, las propiedades y otros miembros del tipo base. A su vez, el tipo base puede derivarse de algún otro tipo, en cuyo caso el tipo derivado hereda los miembros de ambos tipos base en su jerarquía de herencia. Todos los tipos, incluidos los tipos numéricos integrados como Int32 (palabra clave de C#: int), derivan en última instancia de un único tipo base, que es Object (palabra clave de C#: object). Esta jerarquía de tipos unificada se denomina Common Type System (CTS). Para más información sobre la herencia en C#, vea Herencia. En CTS, cada tipo se define como un tipo de valor o un tipo de referencia. Esto incluye todos los tipos personalizados de la biblioteca de clases .NET Framework y también sus propios tipos definidos por el usuario. Los tipos que se definen mediante el uso de la palabra clave struct son tipos de valor; todos los tipos numéricos integrados son structs . Los tipos que se definen mediante el uso de la palabra clave class son tipos de referencia. Los tipos de referencia y los tipos de valor tienen distintas reglas de tiempo de compilación y distintos comportamientos de tiempo de ejecución. En la ilustración siguiente se muestra la relación entre los tipos de valor y los tipos de referencia en CTS.
Tipos de valores y tipos de referencias en CTS NOTA Puede ver que los tipos utilizados con mayor frecuencia están organizados en el espacio de nombres System. Sin embargo, el espacio de nombres que contiene un tipo no tiene ninguna relación con un tipo de valor o un tipo de referencia.
Tipos de valor Los tipos de valor derivan de ValueType, el cual deriva de Object. Los tipos que derivan de ValueType tienen un comportamiento especial en CLR. Las variables de tipo de valor contienen directamente sus valores, lo que significa que la memoria se asigna insertada en cualquier contexto en el que se declare la variable. No se produce ninguna asignación del montón independiente ni sobrecarga de la recolección de elementos no utilizados para las variables de tipo de valor. Existen dos categorías de tipos de valor: struct y enum. Los tipos numéricos integrados son structs y tienen propiedades y métodos a los que se puede obtener acceso: // Static method on type Byte. byte b = Byte.MaxValue;
Pero se declaran y se les asignan valores como si fueran tipos simples no agregados: byte num = 0xA; int i = 5; char c = 'Z';
Los tipos de valor están sellados, lo que significa que, por ejemplo, no puede derivar un tipo de Int32, y no puede definir un struct para que herede de cualquier clase o struct definido por el usuario, porque un struct solo puede heredar de ValueType. A pesar de ello, un struct puede implementar una o más interfaces. Puede convertir un tipo struct en un tipo de interfaz. Esto hace que una operación de conversión boxing encapsule el struct dentro de un objeto de tipo de referencia en el montón administrado. Las operaciones de conversión boxing se producen cuando se pasa un tipo de valor a un método que toma Object como parámetro de entrada. Para más información, vea Conversión boxing y unboxing. Puede usar la palabra clave struct para crear sus propios tipos de valor personalizados. Normalmente, un struct se usa como un contenedor para un pequeño conjunto de variables relacionadas, como se muestra en el ejemplo siguiente: public struct CoOrds { public int x, y; public CoOrds(int p1, int p2) { x = p1; y = p2; } }
Para más información sobre estructuras, vea Structs. Para más información sobre los tipos de valor de .NET Framework, vea Common Type System. La otra categoría de tipos de valor es enum. Una enumeración define un conjunto de constantes integrales con nombre. Por ejemplo, la enumeración FileMode de la biblioteca de clases .NET Framework contiene un conjunto de enteros constantes con nombre que especifican cómo se debe abrir un archivo. Se define como se muestra en el ejemplo siguiente: public enum FileMode { CreateNew = 1, Create = 2, Open = 3, OpenOrCreate = 4, Truncate = 5, Append = 6, }
La constante System.IO.FileMode.Create tiene un valor de 2. Sin embargo, el nombre es mucho más significativo para los humanos que leen el código fuente y, por esa razón, es mejor utilizar enumeraciones en lugar de números literales constantes. Para obtener más información, consulta FileMode. Todas las enumeraciones se heredan de Enum, el cual se hereda de ValueType. Todas las reglas que se aplican a las estructuras también se aplican a las enumeraciones. Para más información sobre las enumeraciones, vea Tipos de enumeración. Tipos de referencia Un tipo que se define como clase, delegado, matriz o interfaz es un tipo de referencia. Al declarar una variable de
un tipo de referencia en tiempo de ejecución, esta contendrá el valor null hasta que se cree expresamente una instancia del objeto mediante el operador new, o bien que se le asigne un objeto creado en otro lugar mediante new , tal y como se muestra en el ejemplo siguiente: MyClass mc = new MyClass(); MyClass mc2 = mc;
Una interfaz debe inicializarse junto con un objeto de clase que lo implementa. Si MyClass implementa IMyInterface , cree una instancia de IMyInterface , tal como se muestra en el ejemplo siguiente: IMyInterface iface = new MyClass();
Cuando se crea el objeto, se asigna la memoria en el montón administrado y la variable solo contiene una referencia a la ubicación del objeto. Los tipos del montón administrado producen sobrecarga cuando se asignan y cuando los reclama la función de administración de memoria automática de CLR, conocida como recolección de elementos no utilizados. En cambio, la recolección de elementos no utilizados también está muy optimizada y no crea problemas de rendimiento en la mayoría de los escenarios. Para obtener más información sobre la recolección de elementos no utilizados, vea Administración de memoria automática. Todas las matrices son tipos de referencia, incluso si sus elementos son tipos de valor. Las matrices derivan de manera implícita de la clase Array, pero el usuario las declara y las usa con la sintaxis simplificada que proporciona C#, como se muestra en el ejemplo siguiente: // Declare and initialize an array of integers. int[] nums = { 1, 2, 3, 4, 5 }; // Access an instance property of System.Array. int len = nums.Length;
Los tipos de referencia admiten la herencia completamente. Al crear una clase, puede heredar de cualquier otra interfaz o clase que no esté definida como sealed; y otras clases pueden heredar de la clase e invalidar sus métodos virtuales. Para más información sobre cómo crear clases propias, vea Clases y structs. Para más información sobre la herencia y los métodos virtuales, vea Herencia.
Tipos de valores literales En C#, los valores literales reciben un tipo del compilador. Puede especificar cómo debe escribirse un literal numérico; para ello, anexe una letra al final del número. Por ejemplo, para especificar que el valor 4.56 debe tratarse como un valor flotante, anexe "f" o "F" después del número: 4.56f . Si no se anexa ninguna letra, el compilador inferirá un tipo para el literal. Para obtener más información sobre los tipos que se pueden especificar con sufijos de letras, vea las páginas de referencia de los tipos individuales en Tipos de valor. Dado que los literales tienen tipo y todos los tipos derivan en última instancia de Object, puede escribir y compilar código como el siguiente: string s = "The answer is " + 5.ToString(); // Outputs: "The answer is 5" Console.WriteLine(s); Type type = 12345.GetType(); // Outputs: "System.Int32" Console.WriteLine(type);
Tipos genéricos Los tipos se pueden declarar con uno o varios parámetros de tipo que actúan como un marcador de posición para el tipo real (el tipo concreto) que proporcionará el código de cliente cuando cree una instancia del tipo. Estos tipos se denominan tipos genéricos. Por ejemplo, el tipo de .NET Framework List tiene un parámetro de tipo al que, por convención, se le denomina T. Cuando crea una instancia del tipo, especifica el tipo de los objetos que contendrá la lista, por ejemplo, la cadena: List stringList = new List(); stringList.Add("String example"); // compile time error adding a type other than a string: stringList.Add(4);
El uso del parámetro de tipo permite reutilizar la misma clase para incluir cualquier tipo de elemento, sin necesidad de convertir cada elemento en object. Las clases de colección genéricas se denominan colecciones fuertemente tipadas porque el compilador conoce el tipo específico de los elementos de la colección y puede generar un error en tiempo de compilación si, por ejemplo, intenta agregar un valor entero al objeto strings del ejemplo anterior. Para más información, vea Genéricos.
Tipos implícitos, tipos anónimos y tipos que aceptan valores NULL Como se ha mencionado anteriormente, puede asignar implícitamente un tipo a una variable local (pero no miembros de clase) mediante la palabra clave var. La variable sigue recibiendo un tipo en tiempo de compilación, pero este lo proporciona el compilador. Para más información, vea Variables locales con asignación implícita de tipos. En algunos casos, resulta conveniente crear un tipo con nombre para conjuntos sencillos de valores relacionados que no desea almacenar ni pasar fuera de los límites del método. Puede crear tipos anónimos para este fin. Para más información, vea Tipos anónimos. Los tipos de valor normales no pueden tener un valor null, pero se pueden crear tipos de valor que aceptan valores NULL mediante la adición de ? después del tipo. Por ejemplo, int? es un tipo int que también puede tener el valor null. En CTS, los tipos que aceptan valores NULL son instancias del tipo struct genérico Nullable. Los tipos que aceptan valores NULL son especialmente útiles cuando se pasan datos hacia y desde bases de datos en las que los valores numéricos podrían ser nulos. Para más información, vea Tipos que aceptan valores NULL.
Secciones relacionadas Para obtener más información, vea los temas siguientes: Conversiones de tipos Conversión boxing y conversión unboxing Uso de tipo dinámico Tipos de valor Tipos de referencia Clases y structs Tipos anónimos Genéricos
Especificación del lenguaje C#
Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Vea también Referencia de C# Guía de programación de C# Conversión de tipos de datos XML Tabla de tipos enteros
Código no seguro y punteros (Guía de programación de C#) 03/10/2017 • 1 min to read • Edit Online
Para mantener la seguridad de tipos, C# no admite la aritmética de puntero de forma predeterminada. En cambio, mediante el uso de la palabra clave unsafe, puede definir un contexto no seguro en el que se pueden usar punteros. Para obtener más información sobre los punteros, vea Tipos de puntero. NOTA En Common Language Runtime (CLR), el código no seguro se conoce como código no comprobable. El código no seguro en C# no es necesariamente peligroso; solo es código cuya seguridad no puede comprobar CLR. Por lo tanto, CLR solo ejecutará código no seguro si se encuentra en un ensamblado de plena confianza. Si usa código no seguro, es su responsabilidad asegurarse de que el código no presenta riesgos de seguridad o errores de puntero.
Información general sobre el código no seguro El código no seguro tiene las propiedades siguientes: Los métodos, tipos y bloques de código se pueden definir como no seguros. En algunos casos, el código no seguro puede aumentar el rendimiento de la aplicación al eliminar las comprobaciones de límites de matriz. El código no seguro es necesario al llamar a funciones nativas que requieren punteros. El código no seguro presenta riesgos para la seguridad y la estabilidad. Para que C# compile código no seguro, la aplicación debe compilarse con /unsafe.
Secciones relacionadas Para obtener más información, consulte: Tipos de puntero Búferes de tamaño fijo Cómo: Utilizar punteros para copiar una matriz de bytes unsafe
Especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Vea también Guía de programación de C#
Comentarios de documentación XML (Guía de programación de C#) 03/10/2017 • 1 min to read • Edit Online
En Visual C# puede crear documentación para el código incluyendo elementos XML en campos de comentario especiales (se indica con barras diagonales triples) en el código fuente directamente delante del bloque de código al que hacen referencia los comentarios, por ejemplo: /// /// This class performs an important function. /// public class MyClass{}
Cuando se compila con la opción /doc, el compilador buscará todas las etiquetas XML en el código fuente y creará un archivo de documentación XML. Para crear la documentación final basada en el archivo generado por el compilador, puede crear una herramienta personalizada o usar una herramienta como Sandcastle. Para hacer referencia a elementos XML (por ejemplo, la función procesa los elementos XML concretos que desea describir en un comentario de documentación XML), puede usar el mecanismo de entrecomillado estándar ( < y > ). Para hacer referencia a identificadores genéricos en elementos de referencia de código ( cref ), puede usar los caracteres de escape (por ejemplo, cref="List" ) o llaves ( cref="List{T}" ). Como caso especial, el compilador analiza las llaves como corchetes angulares para que la creación del comentario de documentación resulte menos complicada al hacer referencia a identificadores genéricos. NOTA Los comentarios de documentación XML no son metadatos; no se incluyen en el ensamblado compilado y, por tanto, no se puede obtener acceso a ellos mediante reflexión.
En esta sección Etiquetas recomendadas para los comentarios de documentación Procesamiento del archivo XML Delimitadores para etiquetas de documentación Cómo: Usar las características de la documentación XML
Secciones relacionadas Para obtener más información, consulte: /doc (Process Documentation Comments) (/doc [Opciones del compilador de C#])
Especificación del lenguaje C# Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.
Vea también Guía de programación de C#