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


Руководство. Расширение консольного приложения C# и отладка в Visual Studio (часть 2 из 2)

В части 2 этой серии учебников вы немного более подробно изучите функции сборки и отладки Visual Studio, необходимые для ежедневной разработки. Эти функции включают управление несколькими проектами, отладкой и ссылкой на сторонние пакеты. Вы запускаете консольное приложение C#, созданное в части 1 этого руководства,, и изучите некоторые функции интегрированной среды разработки Visual Studio. Это руководство является второй частью серии из двух руководств.

В этом руководстве вы выполните следующие задачи:

  • Добавьте второй проект.
  • Справочные библиотеки и добавление пакетов.
  • Отладка кода.
  • Проверьте завершенный код.

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

Для работы с этой статьей можно использовать одно из следующих приложений калькулятора:

Добавление другого проекта

Практический код включает в себя проекты, объединённые вместе в рамках решения. Вы можете добавить проект библиотеки классов в приложение калькулятора, которое предоставляет некоторые функции калькулятора.

В Visual Studio вы используете команду меню Файл>Добавить>новый проект для добавления нового проекта. Вы также можете щелкнуть решение правой кнопкой мыши в обозревателе решений , чтобы добавить проект из контекстного меню.

  1. В обозревателе решений щелкните правой кнопкой мыши узел решения и выберите Добавить>Новый проект.

  2. В окне Добавление нового проекта в поле поиска введите библиотеку классов. Выберите библиотеку классов C# шаблон проекта, а затем выберите Далее.

    снимок экрана: выбор шаблона проекта библиотеки классов.

  3. На экране Настройка нового проекта введите имя проекта CalculatorLibrary, а затем выберите Далее.

  4. При появлении запроса выберите .NET 3.1. Visual Studio создает новый проект и добавляет его в решение.

    снимок экрана обозревателя решений с добавленным проектом библиотеки классов CalculatorLibrary.

  5. Переименуйте файл Class1.cs на CalculatorLibrary.cs. Чтобы переименовать файл, щелкните правой кнопкой мыши на имени в обозревателе решений и выберите Переименовать, или выберите имя и нажмите клавишу F2, или выберите имя еще раз для ввода текста.

    Сообщение может задать вопрос о том, нужно ли переименовать ссылки на Class1 в файле. Это не имеет значения, как вы отвечаете, так как вы замените код на следующем шаге.

  6. Теперь добавьте ссылку на проект, поэтому первый проект может использовать API, предоставляемые новой библиотекой классов. Щелкните правой кнопкой мыши узел Зависимостей в проекте Калькулятор и выберите команду Добавить ссылку на проект.

    снимок экрана: пункт меню

    Появится диалоговое окно диспетчера ссылок. В этом диалоговом окне можно добавить ссылки на другие проекты, сборки и библиотеки DLL COM, необходимые для проектов.

  7. В диалоговом окне Диспетчера ссылок установите флажок для проекта CalculatorLibrary, а затем нажмите кнопку "OK".

    снимок экрана диалогового окна диспетчера ссылок.

    Ссылка на проект отображается в узле Projects в обозревателе решений .

    снимок экрана обозревателя решений со ссылкой на проект.

  8. В Program.csвыберите класс Calculator и весь его код, а затем нажмите клавиши CTRL +X, чтобы вырезать его. Затем в CalculatorLibrary.csвставьте код в пространство имен CalculatorLibrary.

    Кроме того, добавьте public перед классом Калькулятора, чтобы предоставить его вне библиотеки.

    CalculatorLibrary.cs теперь должен выглядеть примерно так:

    // CalculatorLibrary.cs
    using System;
    
     namespace CalculatorLibrary
     {
         public class Calculator
         {
             public static double DoOperation(double num1, double num2, string op)
             {
                 double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.
    
                 // Use a switch statement to do the math.
                 switch (op)
                 {
                     case "a":
                         result = num1 + num2;
                         break;
                     case "s":
                         result = num1 - num2;
                         break;
                     case "m":
                         result = num1 * num2;
                         break;
                     case "d":
                         // Ask the user to enter a non-zero divisor.
                         if (num2 != 0)
                         {
                             result = num1 / num2;
                         }
                         break;
                     // Return text for an incorrect option entry.
                     default:
                         break;
                 }
                 return result;
             }
         }
     }
    
  9. Program.cs также содержит ссылку, но ошибка говорит, что вызов Calculator.DoOperation не разрешается. Ошибка возникает из-за того, что CalculatorLibrary находится в другом пространстве имен. Для полной ссылки можно добавить пространство имен CalculatorLibrary в вызов Calculator.DoOperation в Program.cs:

    // Program.cs
    result = CalculatorLibrary.Calculator.DoOperation(cleanNum1, cleanNum2, op);
    

    Кроме того, можно попробовать добавить директиву using в начало файла Program.cs:

    // Program.cs
    using CalculatorLibrary;
    

    Добавление директивы using должно позволить удалить пространство имен CalculatorLibrary из места вызова, но теперь возникает неоднозначность. Calculator - это класс в CalculatorLibrary, или Calculator - пространство имен?

    Чтобы устранить неоднозначность, переименуйте пространство имен из Calculator в CalculatorProgram в Program.cs.

    // Program.cs
    namespace CalculatorProgram
    
  1. В обозревателе решений щелкните правой кнопкой мыши узел решения и выберите Добавить>Новый проект.

  2. В окне Добавление нового проекта в поле поиска введите библиотеку классов. Выберите библиотеку классов C# шаблон проекта, а затем выберите Далее.

    снимок экрана: выбор шаблона проекта библиотеки классов.

  3. На экране Настройка нового проекта введите имя проекта CalculatorLibrary, а затем выберите Далее.

  4. На экране Дополнительные сведения выбрана версия .NET 8.0. Выберите Создать.

    Visual Studio создает новый проект и добавляет его в решение.

    снимок экрана обозревателя решений с добавленным проектом библиотеки классов CalculatorLibrary.

  5. Переименуйте файл Class1.cs на CalculatorLibrary.cs. Чтобы переименовать файл, щелкните правой кнопкой мыши на имени в обозревателе решений и выберите Переименовать, или выберите имя и нажмите клавишу F2, или выберите имя еще раз для ввода текста.

    Сообщение может попросить переименовать все ссылки на Class1 в файле. Это не имеет значения, как вы отвечаете, так как вы замените код на следующем шаге.

  6. Теперь добавьте ссылку на проект, поэтому первый проект может использовать API, предоставляемые новой библиотекой классов. Щелкните правой кнопкой мыши узел Зависимостей в проекте Калькулятор и выберите команду Добавить ссылку на проект.

    снимок экрана: пункт меню

    Появится диалоговое окно диспетчера ссылок. В этом диалоговом окне можно добавить ссылки на другие проекты, сборки и библиотеки DLL COM, необходимые для проектов.

  7. В диалоговом окне Диспетчера ссылок установите флажок для проекта CalculatorLibrary, а затем нажмите кнопку "OK".

    снимок экрана диалогового окна диспетчера ссылок.

    Ссылка на проект отображается в узле Projects в обозревателе решений .

    снимок экрана обозревателя решений со ссылкой на проект.

  8. В Program.csвыберите класс Calculator и весь его код, а затем нажмите клавиши CTRL +X, чтобы вырезать его. Затем в CalculatorLibrary.csвставьте код в пространство имен CalculatorLibrary.

    Кроме того, добавьте public перед классом Калькулятора, чтобы предоставить его вне библиотеки.

    CalculatorLibrary.cs теперь должен выглядеть примерно так:

     // CalculatorLibrary.cs
     namespace CalculatorLibrary
     {
         public class Calculator
         {
             public static double DoOperation(double num1, double num2, string op)
             {
                 double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.
    
                 // Use a switch statement to do the math.
                 switch (op)
                 {
                     case "a":
                         result = num1 + num2;
                         break;
                     case "s":
                         result = num1 - num2;
                         break;
                     case "m":
                         result = num1 * num2;
                         break;
                     case "d":
                         // Ask the user to enter a non-zero divisor.
                         if (num2 != 0)
                         {
                             result = num1 / num2;
                         }
                         break;
                     // Return text for an incorrect option entry.
                     default:
                         break;
                 }
                 return result;
             }
         }
     }
    
  9. Program.cs также содержит ссылку, но ошибка говорит, что вызов Calculator.DoOperation не разрешается. Ошибка возникает из-за того, что CalculatorLibrary находится в другом пространстве имен. Для полной ссылки можно добавить пространство имен CalculatorLibrary в вызов Calculator.DoOperation в Program.cs:

    // Program.cs
    result = CalculatorLibrary.Calculator.DoOperation(cleanNum1, cleanNum2, op);
    

    Кроме того, можно попробовать добавить директиву using в начало файла Program.cs:

    // Program.cs
    using CalculatorLibrary;
    

    Добавление директивы using должно позволить удалить пространство имен CalculatorLibrary из места вызова.

    Если код Program.cs находится в пространстве имен Calculator, переименуйте пространство имен из Calculator в CalculatorProgram, чтобы удалить неоднозначность между именем класса и именем пространства имен.

Справочные библиотеки .NET: запись в журнал

Класс Trace .NET можно использовать для добавления журнала всех операций и записи в текстовый файл. Класс Trace также полезен для основных методов отладки печати. Класс Trace находится в System.Diagnosticsи использует классы System.IO, такие как StreamWriter.

  1. Начните с добавления директив using в верхней части CalculatorLibrary.cs:

    // CalculatorLibrary.cs
    using System.IO;
    using System.Diagnostics;
    
  2. Это использование класса Trace должно удерживать ссылку на класс, который он ассоциирует с потоком данных файла. Это требование означает, что калькулятор работает лучше как объект, поэтому добавьте конструктор в начале класса Calculator в CalculatorLibrary.cs.

    Также удалите ключевое слово static, чтобы изменить статический метод DoOperation в метод-член.

    // CalculatorLibrary.cs
    public Calculator()
       {
           StreamWriter logFile = File.CreateText("calculator.log");
           Trace.Listeners.Add(new TextWriterTraceListener(logFile));
           Trace.AutoFlush = true;
           Trace.WriteLine("Starting Calculator Log");
           Trace.WriteLine(String.Format("Started {0}", System.DateTime.Now.ToString()));
       }
    
    public double DoOperation(double num1, double num2, string op)
       {
    
  3. Добавьте выходные данные журнала в каждый расчет. DoOperation теперь должен выглядеть следующим кодом:

    // CalculatorLibrary.cs
    public double DoOperation(double num1, double num2, string op)
    {
         double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.
    
         // Use a switch statement to do the math.
         switch (op)
         {
             case "a":
                 result = num1 + num2;
                 Trace.WriteLine(String.Format("{0} + {1} = {2}", num1, num2, result));
                 break;
             case "s":
                 result = num1 - num2;
                 Trace.WriteLine(String.Format("{0} - {1} = {2}", num1, num2, result));
                 break;
             case "m":
                 result = num1 * num2;
                 Trace.WriteLine(String.Format("{0} * {1} = {2}", num1, num2, result));
                 break;
             case "d":
                 // Ask the user to enter a non-zero divisor.
                 if (num2 != 0)
                 {
                     result = num1 / num2;
                     Trace.WriteLine(String.Format("{0} / {1} = {2}", num1, num2, result));
                 }
                     break;
             // Return text for an incorrect option entry.
             default:
                 break;
         }
         return result;
     }
    
  4. Вернувшись в Program.cs, красное волнистое подчеркивание теперь помечает статический вызов. Чтобы устранить ошибку, создайте переменную calculator, добавив следующую строку кода непосредственно перед циклом while (!endApp):

    // Program.cs
    Calculator calculator = new Calculator();
    

    Также измените точку вызова DoOperation, чтобы ссылаться на объект с именем calculator в нижнем регистре. Теперь код является вызовом элемента, а не вызовом статического метода.

    // Program.cs
    result = calculator.DoOperation(cleanNum1, cleanNum2, op);
    
  5. Снова запустите приложение. По завершении щелкните правой кнопкой мыши узел проекта Калькулятора и выберите Открыть папку в Проводнике.

  6. В проводнике перейдите в выходную папку в разделе bin/Debug/net8.0 (или любую используемую версию .NET) и откройте файл calculator.log. Выходные данные должны выглядеть примерно так:

    Starting Calculator Log
    Started 7/9/2020 1:58:19 PM
    1 + 2 = 3
    3 * 3 = 9
    

На этом этапе CalculatorLibrary.cs должен выглядеть так:

// CalculatorLibrary.cs
using System;
using System.IO;
using System.Diagnostics;

namespace CalculatorLibrary
{
    public class Calculator
    {

        public Calculator()
        {
            StreamWriter logFile = File.CreateText("calculator.log");
            Trace.Listeners.Add(new TextWriterTraceListener(logFile));
            Trace.AutoFlush = true;
            Trace.WriteLine("Starting Calculator Log");
            Trace.WriteLine(String.Format("Started {0}", System.DateTime.Now.ToString()));
        }

        public double DoOperation(double num1, double num2, string op)
        {
            double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.

            // Use a switch statement to do the math.
            switch (op)
            {
                case "a":
                    result = num1 + num2;
                    Trace.WriteLine(String.Format("{0} + {1} = {2}", num1, num2, result));
                    break;
                case "s":
                    result = num1 - num2;
                    Trace.WriteLine(String.Format("{0} - {1} = {2}", num1, num2, result));
                    break;
                case "m":
                    result = num1 * num2;
                    Trace.WriteLine(String.Format("{0} * {1} = {2}", num1, num2, result));
                    break;
                case "d":
                    // Ask the user to enter a non-zero divisor.
                    if (num2 != 0)
                    {
                        result = num1 / num2;
                        Trace.WriteLine(String.Format("{0} / {1} = {2}", num1, num2, result));
                    }
                    break;
                // Return text for an incorrect option entry.
                default:
                    break;
            }
            return result;
        }
    }
}

Program.cs должен выглядеть следующим кодом:

// Program.cs
using System;
using CalculatorLibrary;

namespace CalculatorProgram
{

    class Program
    {
        static void Main(string[] args)
        {
            bool endApp = false;
            // Display title as the C# console calculator app.
            Console.WriteLine("Console Calculator in C#\r");
            Console.WriteLine("------------------------\n");

            Calculator calculator = new Calculator();
            while (!endApp)
            {
                // Declare variables and set to empty.
                string numInput1 = "";
                string numInput2 = "";
                double result = 0;

                // Ask the user to type the first number.
                Console.Write("Type a number, and then press Enter: ");
                numInput1 = Console.ReadLine();

                double cleanNum1 = 0;
                while (!double.TryParse(numInput1, out cleanNum1))
                {
                    Console.Write("This is not valid input. Please enter an integer value: ");
                    numInput1 = Console.ReadLine();
                }

                // Ask the user to type the second number.
                Console.Write("Type another number, and then press Enter: ");
                numInput2 = Console.ReadLine();

                double cleanNum2 = 0;
                while (!double.TryParse(numInput2, out cleanNum2))
                {
                    Console.Write("This is not valid input. Please enter an integer value: ");
                    numInput2 = Console.ReadLine();
                }

                // Ask the user to choose an operator.
                Console.WriteLine("Choose an operator from the following list:");
                Console.WriteLine("\ta - Add");
                Console.WriteLine("\ts - Subtract");
                Console.WriteLine("\tm - Multiply");
                Console.WriteLine("\td - Divide");
                Console.Write("Your option? ");

                string op = Console.ReadLine();

                try
                {
                    result = calculator.DoOperation(cleanNum1, cleanNum2, op); 
                    if (double.IsNaN(result))
                    {
                        Console.WriteLine("This operation will result in a mathematical error.\n");
                    }
                    else Console.WriteLine("Your result: {0:0.##}\n", result);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message);
                }

                Console.WriteLine("------------------------\n");

                // Wait for the user to respond before closing.
                Console.Write("Press 'n' and Enter to close the app, or press any other key and Enter to continue: ");
                if (Console.ReadLine() == "n") endApp = true;

                Console.WriteLine("\n"); // Friendly linespacing.
            }
            return;
        }
    }
}

Класс Trace .NET можно использовать для добавления журнала всех операций и записи в текстовый файл. Класс Trace также полезен для основных методов отладки печати. Класс Trace находится в System.Diagnosticsи использует классы System.IO, такие как StreamWriter.

  1. Начните с добавления директив using в верхней части CalculatorLibrary.cs:

    // CalculatorLibrary.cs
    using System.Diagnostics;
    
  2. Это использование класса Trace должно удерживать ссылку на класс, который он ассоциирует с потоком данных файла. Это требование означает, что калькулятор работает лучше как объект, поэтому добавьте конструктор в начале класса Calculator в CalculatorLibrary.cs.

    Также удалите ключевое слово static, чтобы изменить статический метод DoOperation в метод-член.

    // CalculatorLibrary.cs
    public Calculator()
       {
           StreamWriter logFile = File.CreateText("calculator.log");
           Trace.Listeners.Add(new TextWriterTraceListener(logFile));
           Trace.AutoFlush = true;
           Trace.WriteLine("Starting Calculator Log");
           Trace.WriteLine(String.Format("Started {0}", System.DateTime.Now.ToString()));
       }
    
    public double DoOperation(double num1, double num2, string op)
       {
    
  3. Добавьте выходные данные журнала в каждый расчет. DoOperation теперь должен выглядеть следующим кодом:

    // CalculatorLibrary.cs
    public double DoOperation(double num1, double num2, string op)
    {
         double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.
    
         // Use a switch statement to do the math.
         switch (op)
         {
             case "a":
                 result = num1 + num2;
                 Trace.WriteLine(String.Format("{0} + {1} = {2}", num1, num2, result));
                 break;
             case "s":
                 result = num1 - num2;
                 Trace.WriteLine(String.Format("{0} - {1} = {2}", num1, num2, result));
                 break;
             case "m":
                 result = num1 * num2;
                 Trace.WriteLine(String.Format("{0} * {1} = {2}", num1, num2, result));
                 break;
             case "d":
                 // Ask the user to enter a non-zero divisor.
                 if (num2 != 0)
                 {
                     result = num1 / num2;
                     Trace.WriteLine(String.Format("{0} / {1} = {2}", num1, num2, result));
                 }
                     break;
             // Return text for an incorrect option entry.
             default:
                 break;
         }
         return result;
     }
    
  4. Вернувшись в Program.cs, красное волнистое подчеркивание теперь помечает статический вызов. Чтобы устранить ошибку, создайте переменную calculator, добавив следующую строку кода непосредственно перед циклом while (!endApp):

    // Program.cs
    Calculator calculator = new Calculator();
    

    Также измените точку вызова DoOperation, чтобы ссылаться на объект с именем calculator в нижнем регистре. Теперь код является вызовом элемента, а не вызовом статического метода.

    // Program.cs
    result = calculator.DoOperation(cleanNum1, cleanNum2, op);
    
  5. Снова запустите приложение. По завершении щелкните правой кнопкой мыши узел проекта Калькулятора и выберите Открыть папку в Проводнике.

  6. В проводнике перейдите к выходной папке в разделе bin/Debug/и откройте файл calculator.log. Выходные данные должны выглядеть примерно так:

    Starting Calculator Log
    Started 7/9/2020 1:58:19 PM
    1 + 2 = 3
    3 * 3 = 9
    

На этом этапе CalculatorLibrary.cs должен выглядеть так:

// CalculatorLibrary.cs
using System.Diagnostics;

namespace CalculatorLibrary
{
    public class Calculator
    {

        public Calculator()
        {
            StreamWriter logFile = File.CreateText("calculator.log");
            Trace.Listeners.Add(new TextWriterTraceListener(logFile));
            Trace.AutoFlush = true;
            Trace.WriteLine("Starting Calculator Log");
            Trace.WriteLine(String.Format("Started {0}", System.DateTime.Now.ToString()));
        }

        public double DoOperation(double num1, double num2, string op)
        {
            double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.

            // Use a switch statement to do the math.
            switch (op)
            {
                case "a":
                    result = num1 + num2;
                    Trace.WriteLine(String.Format("{0} + {1} = {2}", num1, num2, result));
                    break;
                case "s":
                    result = num1 - num2;
                    Trace.WriteLine(String.Format("{0} - {1} = {2}", num1, num2, result));
                    break;
                case "m":
                    result = num1 * num2;
                    Trace.WriteLine(String.Format("{0} * {1} = {2}", num1, num2, result));
                    break;
                case "d":
                    // Ask the user to enter a non-zero divisor.
                    if (num2 != 0)
                    {
                        result = num1 / num2;
                        Trace.WriteLine(String.Format("{0} / {1} = {2}", num1, num2, result));
                    }
                    break;
                // Return text for an incorrect option entry.
                default:
                    break;
            }
            return result;
        }
    }
}

Program.cs должен выглядеть следующим кодом:

// Program.cs
using CalculatorLibrary;

namespace CalculatorProgram
{

    class Program
    {
        static void Main(string[] args)
        {
            bool endApp = false;
            // Display title as the C# console calculator app.
            Console.WriteLine("Console Calculator in C#\r");
            Console.WriteLine("------------------------\n");

            Calculator calculator = new Calculator();
            while (!endApp)
            {
                // Declare variables and set to empty.
                // Use Nullable types (with ?) to match type of System.Console.ReadLine
                string? numInput1 = "";
                string? numInput2 = "";
                double result = 0;

                // Ask the user to type the first number.
                Console.Write("Type a number, and then press Enter: ");
                numInput1 = Console.ReadLine();

                double cleanNum1 = 0;
                while (!double.TryParse(numInput1, out cleanNum1))
                {
                    Console.Write("This is not valid input. Please enter an integer value: ");
                    numInput1 = Console.ReadLine();
                }

                // Ask the user to type the second number.
                Console.Write("Type another number, and then press Enter: ");
                numInput2 = Console.ReadLine();

                double cleanNum2 = 0;
                while (!double.TryParse(numInput2, out cleanNum2))
                {
                    Console.Write("This is not valid input. Please enter an integer value: ");
                    numInput2 = Console.ReadLine();
                }

                // Ask the user to choose an operator.
                Console.WriteLine("Choose an operator from the following list:");
                Console.WriteLine("\ta - Add");
                Console.WriteLine("\ts - Subtract");
                Console.WriteLine("\tm - Multiply");
                Console.WriteLine("\td - Divide");
                Console.Write("Your option? ");

                string? op = Console.ReadLine();

                // Validate input is not null, and matches the pattern
                if (op == null || ! Regex.IsMatch(op, "[a|s|m|d]"))
                {
                   Console.WriteLine("Error: Unrecognized input.");
                }
                else
                { 
                   try
                   {
                       result = calculator.DoOperation(cleanNum1, cleanNum2, op); 
                       if (double.IsNaN(result))
                       {
                           Console.WriteLine("This operation will result in a mathematical error.\n");
                       }
                       else Console.WriteLine("Your result: {0:0.##}\n", result);
                   }
                   catch (Exception e)
                   {
                       Console.WriteLine("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message);
                   }
                }
                Console.WriteLine("------------------------\n");

                // Wait for the user to respond before closing.
                Console.Write("Press 'n' and Enter to close the app, or press any other key and Enter to continue: ");
                if (Console.ReadLine() == "n") endApp = true;

                Console.WriteLine("\n"); // Friendly linespacing.
            }
            return;
        }
    }
}

Добавление пакета NuGet: запись в JSON-файл

Чтобы вывести операции в формате JSON, популярный и переносимый формат для хранения данных объектов, можно ссылаться на пакет Newtonsoft.Json NuGet. Пакеты NuGet — это основной метод распространения для библиотек классов .NET.

  1. В обозревателе решений щелкните правой кнопкой мыши узел зависимости для проекта CalculatorLibrary и выберите Управление пакетами NuGet.

    снимок экрана: управление пакетами NuGet в контекстном меню.

    снимок экрана: управление пакетами NuGet в контекстном меню.

    Откроется диспетчер пакетов NuGet.

    снимок экрана диспетчера пакетов NuGet.

  2. Найдите и выберите пакет Newtonsoft.Json, затем нажмите "Установить" .

    снимок экрана информации о пакете Newtonsoft JSON NuGet в диспетчере пакетов NuGet.

    Visual Studio скачивает пакет и добавляет его в проект. Новая запись отображается в узле "Ссылки" в обозревателе решений.

    снимок экрана информации о пакете Newtonsoft JSON NuGet в диспетчере пакетов NuGet.

    Если вам будет предложено принять изменения, нажмите кнопку ОК.

    Visual Studio скачивает пакет и добавляет его в проект. Новая запись отображается в узле пакетов в обозревателе решений.

    Добавьте директиву using для Newtonsoft.Json в начале CalculatorLibrary.cs.

    // CalculatorLibrary.cs
    using Newtonsoft.Json;
    
  3. Создайте объект-член JsonWriter и замените конструктор Calculator следующим кодом:

         // CalculatorLibrary.cs
         JsonWriter writer;
    
         public Calculator()
         {
             StreamWriter logFile = File.CreateText("calculatorlog.json");
             logFile.AutoFlush = true;
             writer = new JsonTextWriter(logFile);
             writer.Formatting = Formatting.Indented;
             writer.WriteStartObject();
             writer.WritePropertyName("Operations");
             writer.WriteStartArray();
         }
    
  4. Измените метод DoOperation, чтобы добавить код JSON writer:

         // CalculatorLibrary.cs
         public double DoOperation(double num1, double num2, string op)
         {
             double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.
             writer.WriteStartObject();
             writer.WritePropertyName("Operand1");
             writer.WriteValue(num1);
             writer.WritePropertyName("Operand2");
             writer.WriteValue(num2);
             writer.WritePropertyName("Operation");
             // Use a switch statement to do the math.
             switch (op)
             {
                 case "a":
                     result = num1 + num2;
                     writer.WriteValue("Add");
                     break;
                 case "s":
                     result = num1 - num2;
                     writer.WriteValue("Subtract");
                     break;
                 case "m":
                     result = num1 * num2;
                     writer.WriteValue("Multiply");
                     break;
                 case "d":
                     // Ask the user to enter a non-zero divisor.
                     if (num2 != 0)
                     {
                         result = num1 / num2;
                     }
                     writer.WriteValue("Divide");
                     break;
                 // Return text for an incorrect option entry.
                 default:
                     break;
             }
             writer.WritePropertyName("Result");
             writer.WriteValue(result);
             writer.WriteEndObject();
    
             return result;
         }
    
  5. Добавьте метод для завершения синтаксиса JSON после того, как пользователь завершит ввод данных операции.

     // CalculatorLibrary.cs
     public void Finish()
     {
         writer.WriteEndArray();
         writer.WriteEndObject();
         writer.Close();
     }
    
  6. В конце файла Program.cs, перед return;, добавьте вызов Finish:

         // Program.cs
             // Add call to close the JSON writer before return
             calculator.Finish();
             return;
         }
    
  7. Создайте и запустите приложение, а после ввода нескольких операций закройте приложение, введя команду n.

  8. Откройте файл calculatorlog.json в проводнике. Должно появиться примерно следующее содержимое:

    {
     "Operations": [
         {
         "Operand1": 2.0,
         "Operand2": 3.0,
         "Operation": "Add",
         "Result": 5.0
         },
         {
         "Operand1": 3.0,
         "Operand2": 4.0,
         "Operation": "Multiply",
         "Result": 12.0
         }
     ]
    }
    

Отладка: установка и срабатывание точки останова

Отладчик Visual Studio — это мощный инструмент. Отладчик может пошагово просмотреть ваш код, чтобы найти точный момент, где возникла ошибка программирования. Затем вы можете понять, какие исправления необходимо внести, и внести временные изменения, чтобы продолжить работу приложения.

  1. В Program.csщелкните в области поля слева от следующей строки кода. Вы также можете щелкнуть в строке и выбрать F9, или щелкнуть правой кнопкой мыши в строке и выбрать точку останова>Вставить точку останова.

    // Program.cs
    result = calculator.DoOperation(cleanNum1, cleanNum2, op);
    

    Красная точка, которая отображается, указывает точку останова. Точки останова можно использовать для приостановки приложения и проверки кода. Точку останова можно задать в любой исполняемой строке кода.

    снимок экрана, показывающий настройку точки останова.

  2. Создайте и запустите приложение. Введите следующие значения для вычисления:

    • Для первого номера введите 8.
    • Для второго номера введите 0.
    • Для оператора давайте повеселимся. Введите d.

    Приложение приостанавливает выполнение в месте, где вы создали точку останова, что обозначается желтым указателем слева и выделенным кодом. Выделенный код еще не выполнен.

    снимок экрана с точкой останова

    Теперь, когда приложение приостановлено, вы можете проверить состояние приложения.

Отладка: просмотр переменных

  1. В выделенном коде наведите указатель мыши на переменные, такие как cleanNum1 и op. Текущие значения этих переменных, 8 и d соответственно, отображаются в подсказках данных.

    снимок экрана, на котором показана подсказка данных.

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

  2. В нижней области просмотрите окно Локальные. Если он закрыт, выберите Отладка>Windows>Локальные, чтобы открыть его.

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

    снимок экрана окна

    снимок экрана окна

  3. Посмотрите на окно Автомобили.

    Окно "Авто" аналогично окну Локальные, но отображает переменные, непосредственно предшествующие и следующие за текущей строкой кода, в которой приложение приостановлено.

    Заметка

    Если окно "Авто" не отображается, выберите Отладка>Windows>Авто, чтобы открыть его.

Затем выполните код в отладчике один оператор за раз, который вызывается шаговых.

Отладка: пошаговое выполнение кода

  1. Нажмите F11или выберите Отладка>Вход в функцию.

    С помощью команды Step Into приложение выполняет текущую инструкцию и переходит к следующей исполняемой инструкции, как правило, следующей строке кода. Жёлтый индикатор слева всегда указывает на текущее заявление.

    снимок экрана: шаг в команду

    Вы только что перешли к выполнению метода DoOperation в классе Calculator.

  2. Чтобы получить иерархическое представление потока выполнения вашей программы, просмотрите окно стека вызовов . Если он закрыт, выберите Отладка>Windows>стек вызовов, чтобы открыть его.

    снимок экрана стека вызовов

    В этом представлении показан текущий метод Calculator.DoOperation, указанный желтым указателем. Во второй строке показана функция, вызывавшая метод, из метода Main в Program.cs.

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

  3. Нажимайте F10или выберите Отладка>шагенесколько раз, пока приложение не приостановит инструкцию switch.

    // CalculatorLibrary.cs
    switch (op)
    {
    

    Команда Step Over аналогична команде Step Into, за исключением того, что если текущая инструкция вызывает функцию, отладчик запускает код в функции и не приостанавливает выполнение до тех пор, пока функция не возвращается. Перешагивание быстрее, чем шаг с заходом, если вас не интересует определённая функция.

  4. Нажмите F10 еще раз, чтобы приложение приостанавливалось в следующей строке кода.

    // CalculatorLibrary.cs
    if (num2 != 0)
    {
    

    Этот код проверяет случай деления на ноль. Если приложение продолжает работу, оно вызывает общее исключение (ошибку), но вы можете попробовать что-то другое, например, просмотреть фактическое возвращаемое значение на консоли. Одним из вариантов является использование функции отладки редактировать и продолжать, чтобы внести изменения в код, а затем продолжить отладку. Однако существует другой способ временно изменить поток выполнения.

Отладка: проверка временного изменения

  1. Выберите желтый указатель, который в настоящее время приостановлен в инструкции if (num2 != 0), и перетащите его в следующую инструкцию:

    // CalculatorLibrary.cs
    result = num1 / num2;
    

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

  2. Нажмите F10, чтобы выполнить строку кода.

  3. При наведении указателя мыши на переменную result отображается значение Бесконечность. В C#бесконечность — это результат, когда вы разделяете на ноль.

  4. Нажмите F5или выберите Отладка>продолжить отладку.

    Символ бесконечности отображается в консоли в результате математической операции.

  5. Закройте приложение правильно, введя команду n.

Полный код

Ниже приведен полный код для файла CalculatorLibrary.cs после выполнения всех действий.

// CalculatorLibrary.cs
using System;
using System.IO;
using Newtonsoft.Json;

namespace CalculatorLibrary
{
    public class Calculator
    {

        JsonWriter writer;

        public Calculator()
        {
            StreamWriter logFile = File.CreateText("calculatorlog.json");
            logFile.AutoFlush = true;
            writer = new JsonTextWriter(logFile);
            writer.Formatting = Formatting.Indented;
            writer.WriteStartObject();
            writer.WritePropertyName("Operations");
            writer.WriteStartArray();
        }

        public double DoOperation(double num1, double num2, string op)
        {
            double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.
            writer.WriteStartObject();
            writer.WritePropertyName("Operand1");
            writer.WriteValue(num1);
            writer.WritePropertyName("Operand2");
            writer.WriteValue(num2);
            writer.WritePropertyName("Operation");
            // Use a switch statement to do the math.
            switch (op)
            {
                case "a":
                    result = num1 + num2;
                    writer.WriteValue("Add");
                    break;
                case "s":
                    result = num1 - num2;
                    writer.WriteValue("Subtract");
                    break;
                case "m":
                    result = num1 * num2;
                    writer.WriteValue("Multiply");
                    break;
                case "d":
                    // Ask the user to enter a non-zero divisor.
                    if (num2 != 0)
                    {
                        result = num1 / num2;
                    }
                    writer.WriteValue("Divide");
                    break;
                // Return text for an incorrect option entry.
                default:
                    break;
            }
            writer.WritePropertyName("Result");
            writer.WriteValue(result);
            writer.WriteEndObject();

            return result;
        }

        public void Finish()
        {
            writer.WriteEndArray();
            writer.WriteEndObject();
            writer.Close();
        }
    }
}

И вот код для Program.cs:

// Program.cs
using System;
using CalculatorLibrary;

namespace CalculatorProgram
{

    class Program
    {
        static void Main(string[] args)
        {
            bool endApp = false;
            // Display title as the C# console calculator app.
            Console.WriteLine("Console Calculator in C#\r");
            Console.WriteLine("------------------------\n");

            Calculator calculator = new Calculator();
            while (!endApp)
            {
                // Declare variables and set to empty.
                string numInput1 = "";
                string numInput2 = "";
                double result = 0;

                // Ask the user to type the first number.
                Console.Write("Type a number, and then press Enter: ");
                numInput1 = Console.ReadLine();

                double cleanNum1 = 0;
                while (!double.TryParse(numInput1, out cleanNum1))
                {
                    Console.Write("This is not valid input. Please enter an integer value: ");
                    numInput1 = Console.ReadLine();
                }

                // Ask the user to type the second number.
                Console.Write("Type another number, and then press Enter: ");
                numInput2 = Console.ReadLine();

                double cleanNum2 = 0;
                while (!double.TryParse(numInput2, out cleanNum2))
                {
                    Console.Write("This is not valid input. Please enter an integer value: ");
                    numInput2 = Console.ReadLine();
                }

                // Ask the user to choose an operator.
                Console.WriteLine("Choose an operator from the following list:");
                Console.WriteLine("\ta - Add");
                Console.WriteLine("\ts - Subtract");
                Console.WriteLine("\tm - Multiply");
                Console.WriteLine("\td - Divide");
                Console.Write("Your option? ");

                string op = Console.ReadLine();

                try
                {
                    result = calculator.DoOperation(cleanNum1, cleanNum2, op); 
                    if (double.IsNaN(result))
                    {
                        Console.WriteLine("This operation will result in a mathematical error.\n");
                    }
                    else Console.WriteLine("Your result: {0:0.##}\n", result);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message);
                }

                Console.WriteLine("------------------------\n");

                // Wait for the user to respond before closing.
                Console.Write("Press 'n' and Enter to close the app, or press any other key and Enter to continue: ");
                if (Console.ReadLine() == "n") endApp = true;

                Console.WriteLine("\n"); // Friendly linespacing.
            }
            calculator.Finish();
            return;
        }
    }
}

Ниже приведен полный код для файла CalculatorLibrary.cs после выполнения всех действий.

// CalculatorLibrary.cs
using Newtonsoft.Json;

namespace CalculatorLibrary
{
    public class Calculator
    {

        JsonWriter writer;

        public Calculator()
        {
            StreamWriter logFile = File.CreateText("calculatorlog.json");
            logFile.AutoFlush = true;
            writer = new JsonTextWriter(logFile);
            writer.Formatting = Formatting.Indented;
            writer.WriteStartObject();
            writer.WritePropertyName("Operations");
            writer.WriteStartArray();
        }

        public double DoOperation(double num1, double num2, string op)
        {
            double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.
            writer.WriteStartObject();
            writer.WritePropertyName("Operand1");
            writer.WriteValue(num1);
            writer.WritePropertyName("Operand2");
            writer.WriteValue(num2);
            writer.WritePropertyName("Operation");
            // Use a switch statement to do the math.
            switch (op)
            {
                case "a":
                    result = num1 + num2;
                    writer.WriteValue("Add");
                    break;
                case "s":
                    result = num1 - num2;
                    writer.WriteValue("Subtract");
                    break;
                case "m":
                    result = num1 * num2;
                    writer.WriteValue("Multiply");
                    break;
                case "d":
                    // Ask the user to enter a non-zero divisor.
                    if (num2 != 0)
                    {
                        result = num1 / num2;
                    }
                    writer.WriteValue("Divide");
                    break;
                // Return text for an incorrect option entry.
                default:
                    break;
            }
            writer.WritePropertyName("Result");
            writer.WriteValue(result);
            writer.WriteEndObject();

            return result;
        }

        public void Finish()
        {
            writer.WriteEndArray();
            writer.WriteEndObject();
            writer.Close();
        }
    }
}

И вот код для Program.cs:

// Program.cs
using CalculatorLibrary;

namespace CalculatorProgram
{

    class Program
    {
        static void Main(string[] args)
        {
            bool endApp = false;
            // Display title as the C# console calculator app.
            Console.WriteLine("Console Calculator in C#\r");
            Console.WriteLine("------------------------\n");

            Calculator calculator = new Calculator();
            while (!endApp)
            {
                // Declare variables and set to empty.
                // Use Nullable types (with ?) to match type of System.Console.ReadLine
                string? numInput1 = "";
                string? numInput2 = "";
                double result = 0;

                // Ask the user to type the first number.
                Console.Write("Type a number, and then press Enter: ");
                numInput1 = Console.ReadLine();

                double cleanNum1 = 0;
                while (!double.TryParse(numInput1, out cleanNum1))
                {
                    Console.Write("This is not valid input. Please enter an integer value: ");
                    numInput1 = Console.ReadLine();
                }

                // Ask the user to type the second number.
                Console.Write("Type another number, and then press Enter: ");
                numInput2 = Console.ReadLine();

                double cleanNum2 = 0;
                while (!double.TryParse(numInput2, out cleanNum2))
                {
                    Console.Write("This is not valid input. Please enter an integer value: ");
                    numInput2 = Console.ReadLine();
                }

                // Ask the user to choose an operator.
                Console.WriteLine("Choose an operator from the following list:");
                Console.WriteLine("\ta - Add");
                Console.WriteLine("\ts - Subtract");
                Console.WriteLine("\tm - Multiply");
                Console.WriteLine("\td - Divide");
                Console.Write("Your option? ");

                string? op = Console.ReadLine();

                // Validate input is not null, and matches the pattern
                if (op == null || ! Regex.IsMatch(op, "[a|s|m|d]"))
                {
                   Console.WriteLine("Error: Unrecognized input.");
                }
                else
                { 
                   try
                   {
                       result = calculator.DoOperation(cleanNum1, cleanNum2, op); 
                       if (double.IsNaN(result))
                       {
                           Console.WriteLine("This operation will result in a mathematical error.\n");
                       }
                       else Console.WriteLine("Your result: {0:0.##}\n", result);
                   }
                   catch (Exception e)
                   {
                       Console.WriteLine("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message);
                   }
                }
                Console.WriteLine("------------------------\n");

                // Wait for the user to respond before closing.
                Console.Write("Press 'n' and Enter to close the app, or press any other key and Enter to continue: ");
                if (Console.ReadLine() == "n") endApp = true;

                Console.WriteLine("\n"); // Friendly linespacing.
            }
            calculator.Finish();
            return;
        }
    }
}

Дальнейшие действия

Поздравляем с завершением работы с этим руководством! Чтобы узнать больше, перейдите к следующему содержимому: