Compartir vía


Paseo por el lenguaje C#

El lenguaje C# es el lenguaje más popular para la plataforma .NET, un entorno de desarrollo gratuito, multiplataforma y de código abierto. Los programas de C# se pueden ejecutar en muchos dispositivos diferentes, desde dispositivos de Internet de las cosas (IoT) a la nube y entre todas partes. Puede escribir aplicaciones para equipos y servidores móviles, de escritorio y portátiles.

C# es un lenguaje multiplataforma de uso general que hace que los desarrolladores sean productivos al escribir código de alto rendimiento. Con millones de desarrolladores, C# es el lenguaje .NET más popular. C# tiene una amplia compatibilidad con el ecosistema y todas las cargas de trabajo de .NET. Basado en principios orientados a objetos, incorpora muchas características de otros paradigmas, en particular de la programación funcional. Las características de bajo nivel admiten escenarios de alta eficiencia sin necesidad de escribir código no seguro. La mayor parte del entorno de ejecución y las bibliotecas de .NET se escriben en C#, y los avances en C# suelen beneficiar a todos los desarrolladores de .NET.

C# es parte de la familia de lenguajes C. La sintaxis de C# es familiar si ha usado C, C++, JavaScript, TypeScript o Java. Al igual que C y C++, los punto y coma (;) definen el final de las instrucciones. Los identificadores de C# distinguen mayúsculas de minúsculas. C# tiene el mismo uso de llaves, { y }, instrucciones de control como if, else y switch, y construcciones de bucle como for y while. C# también tiene una instrucción foreach para cualquier tipo de colección.

Hola a todos

El programa "Hola mundo" tradicionalmente se usa para presentar un lenguaje de programación. En este caso, se usa C#:

// This line prints "Hello, World" 
Console.WriteLine("Hello, World");

La línea a partir de // es un comentario de una sola línea. Los comentarios de una sola línea de C# comienzan por // y continúan hasta el final de la línea actual. C# también admite comentarios de varias líneas. Los comentarios de varias líneas comienzan con /* y terminan con */. El método WriteLine de la clase Console, que se encuentra en el espacio de nombres System, genera la salida del programa. Esta clase la proporcionan las bibliotecas de clase estándar, a las que, de forma predeterminada, los programas de C# hacen referencia automáticamente. Otro formulario de programa requiere que declare la clase y el método contenedor para el punto de entrada del programa. El compilador sintetiza estos elementos cuando se usan instrucciones de nivel superior.

Este formato alternativo sigue siendo válido y contiene muchos de los conceptos básicos en todos los programas de C#. Muchos ejemplos de C# existentes usan el siguiente formato equivalente:

using System;
namespace TourOfCsharp;

class Program
{
    static void Main()
    {
        // This line prints "Hello, World" 
        Console.WriteLine("Hello, World");
    }
}

El programa "Hello, World" anterior comienza con una using directiva que hace referencia al System espacio de nombres. Los espacios de nombres proporcionan un método jerárquico para organizar las bibliotecas y los programas de C#. Los espacios de nombres contienen tipos y otros espacios de nombres; por ejemplo, el espacio de nombres System contiene varios tipos, como la clase Console a la que se hace referencia en el programa, y varios otros espacios de nombres, como IO y Collections. Una directiva using que hace referencia a un espacio de nombres determinado permite el uso no calificado de los tipos que son miembros de ese espacio de nombres. Debido a la directiva using, puede utilizar el programa Console.WriteLine como abreviatura de System.Console.WriteLine. En el ejemplo anterior, ese espacio de nombres se incluyó implícitamente.

La clase Program declarada por el programa "Hola mundo" tiene un miembro único, el método llamado Main. El método Main se declara con el modificador static. Mientras que los métodos de instancia pueden hacer referencia a una instancia de objeto envolvente determinada utilizando la palabra clave this, los métodos estáticos funcionan sin referencia a un objeto determinado. De manera predeterminada, cuando no hay instrucciones de nivel superior, un método estático denominado Main actúa como punto de entrada de un programa de C#. La clase que contiene el Main método se denomina Programnormalmente .

Sugerencia

Los ejemplos de este artículo le ofrecen un primer vistazo al código de C#. Algunos ejemplos pueden mostrar elementos de C# con los que no está familiarizado. Cuando esté listo para aprender C#, comience con nuestros tutoriales para principiantes o profundice en los vínculos de cada sección. Si tiene experiencia en Java, JavaScript, TypeScript o Python, lea nuestras sugerencias para ayudarle a encontrar la información que necesita para aprender rápidamente C#.

Características conocidas de C#

C# es accesible para principiantes, pero ofrece características avanzadas para desarrolladores experimentados que escriben aplicaciones especializadas. Puede ser productivo rápidamente. Puede obtener más información sobre técnicas especializadas a medida que las necesite para las aplicaciones.

Las aplicaciones de C# se benefician de la administración automática de memoria de .NET Runtime. Las aplicaciones de C# también usan las amplias bibliotecas de runtime proporcionadas por el SDK de .NET. Algunos componentes son independientes de la plataforma, como las bibliotecas del sistema de archivos, colecciones de datos y bibliotecas matemáticas. Otros son específicos de una sola carga de trabajo, como las bibliotecas web de ASP.NET Core o la biblioteca de interfaz de usuario de .NET MAUI. Un ecosistema de código abierto enriquecido en NuGet aumenta las bibliotecas que forman parte del entorno de ejecución. Estas bibliotecas proporcionan aún más componentes que puede usar.

C# es un lenguaje fuertemente tipado. Cada variable que declare tiene un tipo conocido en tiempo de compilación. El compilador o las herramientas de edición indican si usa ese tipo incorrectamente. Puede corregir esos errores antes de ejecutar el programa. Los tipos de datos fundamentales están integrados en el lenguaje y el entorno de ejecución: tipos de valor como int, double, char, tipos de referencia como string, matrices y otras colecciones. A medida que escribe sus programas, crea sus propios tipos. Esos tipos pueden ser tipos struct para valores o tipos class que definen el comportamiento orientado a objetos. Puede agregar el modificador record a los tipos struct o class para que el compilador sintetice el código para las comparaciones de igualdad. También puede crear definiciones interface, que definen un contrato o un conjunto de miembros, que debe proporcionar un tipo que implemente esa interfaz. También puede definir tipos y métodos genéricos. Los genéricos usan parámetros de tipo para proporcionar un marcador de posición para un tipo real cuando se usa.

A medida que escribe código, se definen funciones, también denominadas métodos, como miembros de tipos struct y class. Estos métodos definen el comportamiento de los tipos. Los métodos se pueden sobrecargar, con un número o tipos diferentes de parámetros. Opcionalmente, los métodos pueden devolver un valor. Además de los métodos, los tipos de C# pueden tener propiedades, que son elementos de datos respaldados por funciones denominadas descriptores de acceso. Los tipos de C# pueden definir eventos, que permiten que un tipo notifique a los suscriptores de acciones importantes. C# admite técnicas orientadas a objetos como herencia y polimorfismo para tipos class.

C# usa excepciones para notificar y controlar errores. Esta práctica es familiar si ha usado C++ o Java. El código produce una excepción cuando no puede hacer lo previsto. Otro código, independientemente del número de niveles de la pila de llamadas, puede recuperarse opcionalmente mediante un bloque try - catch.

Características distintivas de C#

Es posible que algunos elementos de C# le resulten menos familiares.

C# proporciona coincidencia de patrones. Esas expresiones permiten inspeccionar los datos y tomar decisiones en función de sus características. La coincidencia de patrones proporciona una excelente sintaxis para el flujo de control en función de los datos. En el código siguiente se muestra cómo se pueden expresar los métodos para las operaciones booleanas and, or y xor mediante la sintaxis de coincidencia de patrones:

public static bool Or(bool left, bool right) =>
    (left, right) switch
    {
        (true, true) => true,
        (true, false) => true,
        (false, true) => true,
        (false, false) => false,
    };

public static bool And(bool left, bool right) =>
    (left, right) switch
    {
        (true, true) => true,
        (true, false) => false,
        (false, true) => false,
        (false, false) => false,
    };
public static bool Xor(bool left, bool right) =>
    (left, right) switch
    {
        (true, true) => false,
        (true, false) => true,
        (false, true) => true,
        (false, false) => false,
    };

Las expresiones de coincidencia de patrones se pueden simplificar mediante _ como captura para cualquier valor. En el ejemplo siguiente, se muestra cómo se puede simplificar el método and:

public static bool ReducedAnd(bool left, bool right) =>
    (left, right) switch
    {
        (true, true) => true,
        (_, _) => false,
    };

Los ejemplos anteriores también declaran tuplas, estructuras de datos ligeras. Una tupla es una secuencia ordenada de valores de longitud fija con nombres opcionales y tipos individuales. Se encierra la secuencia entre los caracteres ( y ). La declaración (left, right) define una tupla con dos valores booleanos: left y right. Cada segmento modificador declara un valor de tupla como (true, true). Las tuplas proporcionan una sintaxis cómoda para declarar un único valor con varios valores.

Las expresiones de colección proporcionan una sintaxis común para proporcionar valores de colección. Puede escribir valores o expresiones entre [ caracteres y ] y el compilador convierte esa expresión en el tipo de colección necesario:

int[] numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
List<string> names = ["Alice", "Bob", "Charlie", "David"];

IEnumerable<int> moreNumbers = [.. numbers, 11, 12, 13];
IEnumerable<string> empty = [];

En el ejemplo anterior se muestran diferentes tipos de colección que se pueden inicializar mediante expresiones de colección. En un ejemplo se usa la [] expresión de colección vacía para declarar una colección vacía. Otro ejemplo usa el ..elemento spread para expandir una colección y agregar todos sus valores a la expresión de colección.

Puede usar expresiones de índice y rango para recuperar uno o varios elementos de una colección indexable:

string second = names[1]; // 0-based index
string last = names[^1]; // ^1 is the last element
int[] smallNumbers = numbers[0..5]; // 0 to 4

El ^ índice indica desde el final en lugar de desde el principio. El ^0 elemento es uno más allá del final de la colección, por lo que ^1 es el último elemento. En .. una expresión de intervalo, se indica el intervalo de elementos que se van a incluir. El intervalo comienza con el primer índice e incluye todos los elementos hasta el índice final, pero sin incluir el elemento en dicho índice.

Language Integrated Query (LINQ) proporciona una sintaxis común basada en patrones para consultar o transformar cualquier colección de datos. LINQ unifica la sintaxis para consultar colecciones en memoria, datos estructurados como XML o JSON, almacenamiento de base de datos e incluso API de datos basadas en la nube. Aprenderá un conjunto de sintaxis y podrá buscar y manipular datos independientemente de su almacenamiento. La consulta siguiente busca todos los alumnos cuyo promedio de calificaciones es mayor que 3,5:

var honorRoll = from student in Students
                where student.GPA > 3.5
                select student;

La consulta anterior funciona para muchos tipos de almacenamiento representados por Students. Podría ser una colección de objetos, una tabla de base de datos, un blob de almacenamiento en la nube o una estructura XML. La misma sintaxis de consulta funciona para todos los tipos de almacenamiento.

El modelo de programación asincrónica basado en tareas permite escribir código que se lee como si se ejecutara sincrónicamente, aunque se ejecuta de forma asincrónica. Utiliza las palabras clave async y await para describir métodos asincrónicos y cuando una expresión se evalúa de forma asincrónica. En el ejemplo siguiente, se espera una solicitud web asincrónica. Cuando se completa la operación asincrónica, el método devuelve la longitud de la respuesta:

public static async Task<int> GetPageLengthAsync(string endpoint)
{
    var client = new HttpClient();
    var uri = new Uri(endpoint);
    byte[] content = await client.GetByteArrayAsync(uri);
    return content.Length;
}

C# también admite una instrucción await foreach para iterar una colección respaldada por una operación asincrónica, como una API de paginación de GraphQL. En el ejemplo siguiente, se leen datos en fragmentos y se devuelve un iterador que proporciona acceso a cada elemento cuando está disponible:

public static async IAsyncEnumerable<int> ReadSequence()
{
    int index = 0;
    while (index < 100)
    {
        int[] nextChunk = await GetNextChunk(index);
        if (nextChunk.Length == 0)
        {
            yield break;
        }
        foreach (var item in nextChunk)
        {
            yield return item;
        }
        index++;
    }
}

Los autores de llamadas pueden iterar la colección mediante una instrucción await foreach:

await foreach (var number in ReadSequence())
{
    Console.WriteLine(number);
}

Por último, como parte del ecosistema de .NET, puede usar Visual Studio o Visual Studio Code con C# DevKit. Estas herramientas proporcionan una comprensión integral de C#, incluido el código que se debe escribir. También proporcionan funcionalidades de depuración.