Compartir a través de


Tutorial: Exploración de ideas con instrucciones de nivel superior para compilar código a medida que aprenda

En este tutorial, aprenderá a:

  • Obtener información sobre las reglas que rigen el uso de las instrucciones de nivel superior.
  • Use instrucciones de nivel superior para explorar algoritmos.
  • Refactorizar exploraciones en componentes reutilizables.

Prerrequisitos

Debe configurar la máquina para ejecutar .NET 6 o posterior. El compilador de C# está disponible a partir de visual Studio 2022 o SDK de .NET.

En este tutorial se da por supuesto que está familiarizado con C# y .NET, incluido Visual Studio o la CLI de .NET.

Empezar a explorar

Las instrucciones de nivel superior permiten evitar la ceremonia adicional requerida colocando el punto de entrada del programa en un método estático en una clase. El punto de partida típico de una nueva aplicación de consola tiene el siguiente aspecto:

using System;

namespace Application
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

El código anterior es el resultado de ejecutar el comando dotnet new console y crear una nueva aplicación de consola. Esas 11 líneas contienen solo una línea de código ejecutable. Puede simplificar ese programa con la nueva funcionalidad de instrucciones de nivel superior. Esto le permite quitar todas las líneas de este programa menos dos:

// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");

Importante

Las plantillas de C# para .NET 6 usan instrucciones de nivel superior. Es posible que la aplicación no coincida con el código de este artículo, si ya ha actualizado a .NET 6. Para obtener más información, consulte el artículo sobre Nuevas plantillas de C# para generar instrucciones de nivel superior

El SDK de .NET 6 también agrega un conjunto de directivas deglobal using implícitas para proyectos que usan los siguientes SDK:

  • Microsoft.NET.Sdk
  • Microsoft.NET.Sdk.Web
  • Microsoft.NET.Sdk.Worker

Estas directivas de global using implícitas incluyen los espacios de nombres más comunes para el tipo de proyecto.

Para saber más, consulte el artículo sobre las directivas de uso implícito

Esta característica simplifica lo necesario para empezar a explorar nuevas ideas. Puede usar las instrucciones de nivel superior para escenarios de scripting o para explorar. Una vez que tenga los conceptos básicos en funcionamiento, puede empezar a refactorizar el código y crear métodos, clases u otros ensamblados para componentes reutilizables que ha compilado. Las instrucciones de nivel superior permiten la experimentación rápida y los tutoriales para principiantes. También proporcionan una transición fluida de la experimentación a programas completos.

Las instrucciones de nivel superior se ejecutan en el orden en que aparecen en el archivo. Las instrucciones de nivel superior solo se pueden usar en un archivo de código fuente de la aplicación. El compilador genera un error si los usa en más de un archivo.

Creación de una máquina de respuesta mágica de .NET

En este tutorial, vamos a crear una aplicación de consola que responda a una pregunta "sí" o "no" con una respuesta aleatoria. Desarrollas la funcionalidad paso a paso. Puede centrarse en la tarea en lugar de en la ceremonia necesaria para la estructura de un programa típico. Después, una vez que esté satisfecho con la funcionalidad, puede refactorizar la aplicación a medida que se ajuste.

Un buen punto de partida es volver a escribir la pregunta en la consola. Puede empezar escribiendo el código siguiente:

Console.WriteLine(args);

No declaras una variable args. Para el archivo de origen único que contiene las instrucciones de nivel superior, el compilador reconoce args para indicar los argumentos de la línea de comandos. El tipo de 'args' es un string[], como sucede en todos los programas C#.

Para probar el código, ejecute el siguiente comando dotnet run:

dotnet run -- Should I use top level statements in all my programs?

Los argumentos después del -- en la línea de comandos se pasan al programa. Puede ver el tipo de la variable args, ya que es lo que se imprime en la consola:

System.String[]

Para escribir la pregunta en la consola, debe enumerar los argumentos y separarlos con un espacio. Reemplace la llamada WriteLine por el código siguiente:

Console.WriteLine();
foreach(var s in args)
{
    Console.Write(s);
    Console.Write(' ');
}
Console.WriteLine();

Ahora, al ejecutar el programa, muestra correctamente la pregunta como una cadena de argumentos.

Responder con una respuesta aleatoria

Después de repetir la pregunta, puede agregar el código para generar la respuesta aleatoria. Empiece agregando una matriz de posibles respuestas:

string[] answers =
[
    "It is certain.",       "Reply hazy, try again.",     "Don’t count on it.",
    "It is decidedly so.",  "Ask again later.",           "My reply is no.",
    "Without a doubt.",     "Better not tell you now.",   "My sources say no.",
    "Yes – definitely.",    "Cannot predict now.",        "Outlook not so good.",
    "You may rely on it.",  "Concentrate and ask again.", "Very doubtful.",
    "As I see it, yes.",
    "Most likely.",
    "Outlook good.",
    "Yes.",
    "Signs point to yes.",
];

Esta matriz tiene 10 respuestas afirmativas, cinco no confirmadas y cinco negativas. A continuación, agregue el código siguiente para generar y mostrar una respuesta aleatoria de la matriz:

var index = new Random().Next(answers.Length - 1);
Console.WriteLine(answers[index]);

Puede volver a ejecutar la aplicación para ver los resultados. Debería ver algo parecido al siguiente resultado:

dotnet run -- Should I use top level statements in all my programs?

Should I use top level statements in all my programs?
Better not tell you now.

Este código responde a las preguntas, pero vamos a agregar una característica más. Le gustaría que la aplicación de preguntas simulase pensar en la respuesta. Puede hacerlo agregando un poco de animación ASCII y pausando mientras trabaja. Agregue el código siguiente después de la línea que repite la pregunta:

for (int i = 0; i < 20; i++)
{
    Console.Write("| -");
    await Task.Delay(50);
    Console.Write("\b\b\b");
    Console.Write("/ \\");
    await Task.Delay(50);
    Console.Write("\b\b\b");
    Console.Write("- |");
    await Task.Delay(50);
    Console.Write("\b\b\b");
    Console.Write("\\ /");
    await Task.Delay(50);
    Console.Write("\b\b\b");
}
Console.WriteLine();

También debe agregar una directiva using a la parte superior del archivo de origen:

using System.Threading.Tasks;

Las directivas using deben aparecer antes que cualquier otra del archivo. De lo contrario, se trata de un error del compilador. Puedes volver a ejecutar el programa y ver la animación. Eso mejora la experiencia. Experimente con la longitud del retraso para que coincida con su gusto.

El código anterior crea un conjunto de líneas giratorias separadas por un espacio. Agregar la palabra clave await indica al compilador que genere el punto de entrada del programa como un método que tenga el modificador async y devuelva un System.Threading.Tasks.Task. Este programa no devuelve un valor, por lo que el punto de entrada del programa devuelve un Task. Si el programa devuelve un valor entero, agregaría una instrucción return al final de las instrucciones de nivel superior. Esa instrucción return especificaría el valor entero que se va a devolver. Si las instrucciones de nivel superior incluyen una expresión de await, el tipo de valor devuelto se convierte en System.Threading.Tasks.Task<TResult>.

Reestructuración del código para el futuro

El programa debe tener un aspecto similar al código siguiente:

Console.WriteLine();
foreach(var s in args)
{
    Console.Write(s);
    Console.Write(' ');
}
Console.WriteLine();

for (int i = 0; i < 20; i++)
{
    Console.Write("| -");
    await Task.Delay(50);
    Console.Write("\b\b\b");
    Console.Write("/ \\");
    await Task.Delay(50);
    Console.Write("\b\b\b");
    Console.Write("- |");
    await Task.Delay(50);
    Console.Write("\b\b\b");
    Console.Write("\\ /");
    await Task.Delay(50);
    Console.Write("\b\b\b");
}
Console.WriteLine();

string[] answers =
[
    "It is certain.",       "Reply hazy, try again.",     "Don't count on it.",
    "It is decidedly so.",  "Ask again later.",           "My reply is no.",
    "Without a doubt.",     "Better not tell you now.",   "My sources say no.",
    "Yes – definitely.",    "Cannot predict now.",        "Outlook not so good.",
    "You may rely on it.",  "Concentrate and ask again.", "Very doubtful.",
    "As I see it, yes.",
    "Most likely.",
    "Outlook good.",
    "Yes.",
    "Signs point to yes.",
];

var index = new Random().Next(answers.Length - 1);
Console.WriteLine(answers[index]);

El código anterior es razonable. Funciona. Pero no es reutilizable. Ahora que la aplicación funciona, es el momento de extraer partes reutilizables.

Un candidato es el código que muestra la animación en espera. Ese fragmento de código puede convertirse en un método:

Puede empezar creando una función local en el archivo. Reemplace la animación actual por el código siguiente:

await ShowConsoleAnimation();

static async Task ShowConsoleAnimation()
{
    for (int i = 0; i < 20; i++)
    {
        Console.Write("| -");
        await Task.Delay(50);
        Console.Write("\b\b\b");
        Console.Write("/ \\");
        await Task.Delay(50);
        Console.Write("\b\b\b");
        Console.Write("- |");
        await Task.Delay(50);
        Console.Write("\b\b\b");
        Console.Write("\\ /");
        await Task.Delay(50);
        Console.Write("\b\b\b");
    }
    Console.WriteLine();
}

El código anterior crea una función local dentro del método main. Ese código todavía no es reutilizable. Por tanto, extraiga ese código en una clase. Cree un archivo denominado utilities.cs y agregue el código siguiente:

namespace MyNamespace
{
    public static class Utilities
    {
        public static async Task ShowConsoleAnimation()
        {
            for (int i = 0; i < 20; i++)
            {
                Console.Write("| -");
                await Task.Delay(50);
                Console.Write("\b\b\b");
                Console.Write("/ \\");
                await Task.Delay(50);
                Console.Write("\b\b\b");
                Console.Write("- |");
                await Task.Delay(50);
                Console.Write("\b\b\b");
                Console.Write("\\ /");
                await Task.Delay(50);
                Console.Write("\b\b\b");
            }
            Console.WriteLine();
        }
    }
}

Un archivo que tiene instrucciones de nivel superior también puede contener espacios de nombres y tipos al final del archivo, después de las instrucciones de nivel superior. Pero para este tutorial, coloca el método de animación en un archivo independiente para que sea más fácil de reutilizar.

Por último, puede limpiar el código de animación para quitar alguna duplicación mediante el bucle foreach para iterar a través de un conjunto de elementos de animación definidos en el array animations.
El método completo ShowConsoleAnimation después de la refactorización debe ser similar al código siguiente:

public static async Task ShowConsoleAnimation()
{
    string[] animations = ["| -", "/ \\", "- |", "\\ /"];
    for (int i = 0; i < 20; i++)
    {
        foreach (string s in animations)
        {
            Console.Write(s);
            await Task.Delay(50);
            Console.Write("\b\b\b");
        }
    }
    Console.WriteLine();
}

Ahora tiene una aplicación completa y refactoriza los elementos reutilizables para su uso posterior. Puede llamar al nuevo método de utilidad desde las instrucciones de nivel superior, como se muestra en la versión finalizada del programa principal:

using MyNamespace;

Console.WriteLine();
foreach(var s in args)
{
    Console.Write(s);
    Console.Write(' ');
}
Console.WriteLine();

await Utilities.ShowConsoleAnimation();

string[] answers =
[
    "It is certain.",       "Reply hazy, try again.",     "Don’t count on it.",
    "It is decidedly so.",  "Ask again later.",           "My reply is no.",
    "Without a doubt.",     "Better not tell you now.",   "My sources say no.",
    "Yes – definitely.",    "Cannot predict now.",        "Outlook not so good.",
    "You may rely on it.",  "Concentrate and ask again.", "Very doubtful.",
    "As I see it, yes.",
    "Most likely.",
    "Outlook good.",
    "Yes.",
    "Signs point to yes.",
];

var index = new Random().Next(answers.Length - 1);
Console.WriteLine(answers[index]);

En el ejemplo anterior se agrega la llamada a Utilities.ShowConsoleAnimationy se agrega otra directiva using.

Resumen

Las instrucciones de nivel superior facilitan la creación de programas sencillos para su uso para explorar nuevos algoritmos. Puede experimentar con algoritmos probando diferentes fragmentos de código. Una vez aprendido lo que funciona, puede refactorizar el código para que sea más fácil de mantener.

Las instrucciones de nivel superior simplifican los programas basados en aplicaciones de consola. Estas aplicaciones incluyen funciones de Azure, acciones de GitHub y otras utilidades pequeñas. Para obtener más información, vea Instrucciones de nivel superior (Guía de programación de C#).