Поделиться через


Учебное пособие: Исследуйте идеи, используя операторы верхнего уровня для создания кода по мере обучения

В этом руководстве описано, как:

  • Изучите правила, регулирующие использование операторов верхнего уровня.
  • Используйте инструкции верхнего уровня для изучения алгоритмов.
  • Преобразование исследований в компоненты для повторного использования.

Необходимые условия

Необходимо настроить компьютер для запуска .NET 6 или более поздней версии. Компилятор C# доступен начиная с Visual Studio 2022 или пакета SDK для .NET.

В этом руководстве предполагается, что вы знакомы с C# и .NET, включая Visual Studio или .NET CLI.

Начало изучения

Инструкции топ-уровня позволяют избежать дополнительной обработки, которая возникает при необходимости размещения точки входа программы в статический метод в классе. Типичный начальный пункт для нового консольного приложения выглядит следующим образом:

using System;

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

Приведенный выше код является результатом выполнения команды dotnet new console и создания консольного приложения. Эти 11 строки содержат только одну строку исполняемого кода. Эту программу можно упростить с помощью новой функции инструкций верхнего уровня. Это позволяет удалить все, кроме двух строк в этой программе:

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

Важный

Шаблоны C# для .NET 6 используют инструкции верхнего уровня . Приложение может не соответствовать коду в этой статье, если вы уже обновили его до .NET 6. Дополнительные сведения см. в статье о новых шаблонах C#, которые создают инструкции на верхнем уровне

Пакет SDK для .NET 6 также добавляет набор неявных директив для проектов, использующих следующие пакеты SDK:

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

Эти неявные директивы global using включают наиболее распространенные пространства имен для типа проекта.

Дополнительные сведения см. в статье о неявных директив using

Эта функция упрощает изучение новых идей. Инструкции верхнего уровня можно использовать для сценариев скриптов или для исследований. После работы с основами можно начать рефакторинг кода и создать методы, классы или другие сборки для созданных повторно используемых компонентов. Инструкции верхнего уровня позволяют быстро экспериментировать и учебные пособия для начинающих. Они также обеспечивают гладкий путь от экспериментирования до полных программ.

Инструкции верхнего уровня выполняются в том порядке, в котором они отображаются в файле. Инструкции верхнего уровня можно использовать только в одном исходном файле в приложении. Компилятор создает ошибку, если они используются в нескольких файлах.

Создание волшебного компьютера ответов .NET

В этом руководстве мы создадим консольное приложение, которое отвечает на вопрос "да" или "нет" с случайным ответом. Вы строите функциональность шаг за шагом. Вы можете сосредоточиться на задаче, а не на церемонии, необходимой для структуры типичной программы. Затем, когда вы удовлетворены функциональностью, вы можете отрефакторить приложение по своему усмотрению.

Хорошая отправная точка — написать вопрос обратно в консоль. Для начала можно написать следующий код:

Console.WriteLine(args);

Вы не объявляете переменную args. Для одного исходного файла, содержащего инструкции верхнего уровня, компилятор распознает args, чтобы означать аргументы командной строки. Тип args — это string[], как и во всех программах C#.

Чтобы протестировать код, выполните следующую команду dotnet run:

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

Аргументы после -- в командной строке передаются программе. Вы можете увидеть тип переменной args, выведенный на консоль.

System.String[]

Чтобы написать вопрос в консоль, необходимо перечислить аргументы и разделить их пробелом. Замените вызов WriteLine следующим кодом:

Console.WriteLine();
foreach(var s in args)
{
    Console.Write(s);
    Console.Write(' ');
}
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.",
];

Этот массив содержит 10 утвердительных ответов, пять нейтральных и пять отрицательных. Затем добавьте следующий код, чтобы создать и отобразить случайный ответ из массива:

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

Вы можете снова запустить приложение, чтобы просмотреть результаты. Вы должны увидеть примерно следующее выходные данные:

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.

Код для создания ответа включает объявление переменной в инструкциях верхнего уровня. Компилятор включает это объявление в созданный компилятором метод Main. Так как эти объявления переменных являются локальными переменными, нельзя включить модификатор static.

Этот код отвечает на вопросы, но добавим еще одну функцию. Вы хотите, чтобы ваше приложение вопросов имитировало мышление об ответе. Это можно сделать, добавив немного анимации ASCII и делая паузы во время работы. Добавьте следующий код после строки, которая отражает вопрос:

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();

Кроме того, необходимо добавить директиву using в начало исходного файла:

using System.Threading.Tasks;

Директивы using должны быть перед любыми другими инструкциями в файле. В противном случае это ошибка компилятора. Вы можете снова запустить программу и увидеть анимацию. Это улучшает опыт. Поэкспериментируйте с длиной задержки, чтобы соответствовать вашему вкусу.

Предыдущий код создает набор вращающихся линий, отделенных друг от друга пробелами. Добавление ключевого слова await указывает компилятору создать точку входа программы в качестве метода с модификатором async и возвращает System.Threading.Tasks.Task. Эта программа не возвращает значение, поэтому точка входа программы возвращает Task. Если программа возвращает целочисленное значение, вы добавите оператор return в конец инструкций верхнего уровня. Этот оператор возврата укажет целочисленное значение, которое следует вернуть. Если в операторах верхнего уровня присутствует выражение await, возвращаемый тип становится System.Threading.Tasks.Task<TResult>.

Рефакторинг для будущего

Программа должна выглядеть следующим образом:

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]);

Приведенный выше код является разумным. Оно работает. Но это не допускает повторного использования. Теперь, когда приложение у вас работает, пришло время извлечь повторно используемые части.

Одним из кандидатов является код, отображающий анимацию ожидания. Этот фрагмент кода может стать методом:

Сначала можно создать локальную функцию в файле. Замените текущую анимацию следующим кодом:

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();
}

Предыдущий код создает локальную функцию внутри основного метода. Этот код по-прежнему не используется повторно. Извлеките этот код в класс. Создайте файл с именем utilities.cs и добавьте следующий код:

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();
        }
    }
}

Файл с операторами верхнего уровня также может содержать пространства имен и типы в конце файла после инструкций верхнего уровня. Но для этого руководства вы помещаете метод анимации в отдельный файл, чтобы сделать его более легко используемым повторно.

Наконец, можно очистить код анимации, чтобы удалить некоторые дублирования, используя цикл foreach для итерации с помощью набора элементов анимации, определенных в массиве animations.
Полный метод ShowConsoleAnimation после рефакторинга должен выглядеть следующим образом:

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();
}

Теперь у вас есть полное приложение, и вы рефакторизовали повторно используемые части для последующего использования. Вы можете вызвать новый метод служебной программы из инструкций верхнего уровня, как показано в готовой версии основной программы:

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]);

В предыдущем примере добавляется вызов Utilities.ShowConsoleAnimationи добавляется ещё одна директива using.

Сводка

Инструкции верхнего уровня упрощают создание простых программ для изучения новых алгоритмов. Вы можете поэкспериментировать с алгоритмами, пробуя различные фрагменты кода. После того как вы узнали, что работает, вы можете рефакторить код, чтобы он стал более поддерживаемым.

Инструкции верхнего уровня упрощают программы, основанные на консольных приложениях. К этим приложениям относятся функции Azure, действия GitHub и другие небольшие служебные программы. Дополнительные сведения см. в инструкций верхнего уровня (руководство по программированию на C#).