Tutorial: estender o aplicativo de console e a depuração do C# no Visual Studio (parte 2 de 2)

Na parte 2 desta série de tutoriais, você se aprofundará um pouco mais nos recursos de build e depuração do Visual Studio necessários para o desenvolvimento diário. Esses recursos incluem o gerenciamento de vários projetos, a depuração e a referência a pacotes de terceiros. Você executará o aplicativo de console do C# criado na Parte 1 deste tutorial e explorará alguns recursos do IDE (ambiente de desenvolvimento integrado) do Visual Studio. Este tutorial é a parte 2 de uma série com duas partes.

Neste tutorial, você completa as seguintes tarefas:

  • Adicione um segundo projeto.
  • Referencie bibliotecas e adicione pacotes.
  • Depure seu código.
  • Inspecione o código concluído.

Pré-requisitos

Para trabalhar com este artigo, você pode usar qualquer um destes aplicativos de calculadora:

Adicionar outro projeto

O código do mundo real envolve projetos que trabalham em conjunto em uma solução. Você pode adicionar um projeto de biblioteca de classes ao aplicativo de calculadora que fornece algumas funções de calculadora.

No Visual Studio, você usa o comando de menu Arquivo>Adicionar>Novo Projeto para adicionar um novo projeto. Você também pode clicar com o botão direito do mouse na solução no Gerenciador de Soluções para adicionar um projeto no menu de contexto.

  1. No Gerenciador de Soluções, clique com o botão direito do mouse no nó da solução e escolha Adicionar>Novo projeto.

  2. Na janela Adicionar um novo projeto, digite biblioteca de classes na caixa de pesquisa. Escolha o modelo de projeto de biblioteca de classes do C# e, em seguida, selecione Avançar.

    Screenshot of Class Library project template selection.

  3. Na tela Configurar seu novo projeto, digite o nome do projeto CalculatorLibrary e selecione Avançar.

  4. Escolha .NET 3.1, quando solicitado. O Visual Studio cria o novo projeto e adiciona à solução.

    Screenshot of Solution Explorer with the CalculatorLibrary class library project added.

  5. Renomeie o arquivo Class1.cs como CalculatorLibrary.cs. Para renomear o arquivo, você pode clicar com o botão direito do mouse no nome do mesmo no Gerenciador de Soluções, escolher Renomear, selecionar o nome e pressionar F2, ou selecionar o nome e selecionar novamente para digitar.

    Uma mensagem pode perguntar se você deseja renomear as referências como Class1 no arquivo. Não importa como você responde, pois o código será substituído em uma próxima etapa.

  6. Agora, adicione uma referência de projeto de modo que o primeiro projeto possa usar as APIs expostas pela nova biblioteca de classes. Clique com o botão direito do mouse no nó Dependências no projeto Calculadora e escolha Adicionar Referência de Projeto.

    Screenshot of the Add Project Reference menu item.

    A caixa de diálogo Gerenciador de Referências é exibida. Nesta caixa de diálogo, você pode adicionar referências a outros projetos, assemblies e COM DLLs necessários para os projetos.

  7. Na caixa de diálogo Gerenciador de Referências, marque a caixa de seleção do projeto CalculatorLibrary e selecione OK.

    Screenshot of the Reference Manager dialog box.

    A referência de projeto será exibida no nó Projetos no Gerenciador de Soluções.

    Screenshot of Solution Explorer with project reference.

  8. Em Program.cs, selecione a classe Calculator e todo o código e pressione Ctrl+X para cortá-la. Em seguida, em CalculatorLibrary.cs, cole o código no namespace CalculatorLibrary.

    Adicione também public antes da classe Calculadora para expô-la fora da biblioteca.

    Agora o CalculatorLibrary.cs deve ser semelhante ao seguinte código:

    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. O Program.cs também tem uma referência, mas um erro diz que a chamada Calculator.DoOperation não está sendo resolvida. Esse erro aparece porque CalculatorLibrary está em um namespace diferente. Para uma referência totalmente qualificada, você pode adicionar o namespace CalculatorLibrary à chamada Calculator.DoOperation:

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

    Ou você pode tentar adicionar uma diretiva using ao início do arquivo:

    using CalculatorLibrary;
    

    Adicionar a diretiva using deve permitir que você remova o namespace CalculatorLibrary do site de chamada, mas agora existe uma ambiguidade. A classe Calculator está em CalculatorLibraryou Calculator é o namespace?

    Para resolver a ambiguidade, renomeie o namespace de Calculator para CalculatorProgram em Program.cs.

    namespace CalculatorProgram
    
  1. No Gerenciador de Soluções, clique com o botão direito do mouse no nó da solução e escolha Adicionar>Novo projeto.

  2. Na janela Adicionar um novo projeto, digite biblioteca de classes na caixa de pesquisa. Escolha o modelo de projeto de biblioteca de classes do C# e, em seguida, selecione Avançar.

    Screenshot of Class Library project template selection.

  3. Na tela Configurar seu novo projeto, digite o nome do projeto CalculatorLibrary e selecione Avançar.

  4. Na tela Informações adicionais, o .NET 8.0 está selecionado. Selecione Criar.

    O Visual Studio cria o novo projeto e adiciona à solução.

    Screenshot of Solution Explorer with the CalculatorLibrary class library project added.

  5. Renomeie o arquivo Class1.cs como CalculatorLibrary.cs. Para renomear o arquivo, você pode clicar com o botão direito do mouse no nome do mesmo no Gerenciador de Soluções, escolher Renomear, selecionar o nome e pressionar F2, ou selecionar o nome e selecionar novamente para digitar.

    Uma mensagem pode perguntar se você deseja renomear todas as referências como Class1 no arquivo. Não importa como você responde, pois o código será substituído em uma próxima etapa.

  6. Agora, adicione uma referência de projeto de modo que o primeiro projeto possa usar as APIs expostas pela nova biblioteca de classes. Clique com o botão direito do mouse no nó Dependências no projeto Calculadora e escolha Adicionar Referência de Projeto.

    Screenshot of the Add Project Reference menu item.

    A caixa de diálogo Gerenciador de Referências é exibida. Nesta caixa de diálogo, você pode adicionar referências a outros projetos, assemblies e COM DLLs necessários para os projetos.

  7. Na caixa de diálogo Gerenciador de Referências, marque a caixa de seleção do projeto CalculatorLibrary e selecione OK.

    Screenshot of the Reference Manager dialog box.

    A referência de projeto será exibida no nó Projetos no Gerenciador de Soluções.

    Screenshot of Solution Explorer with project reference.

  8. Em Program.cs, selecione a classe Calculator e todo o código e pressione Ctrl+X para cortá-la. Em seguida, em CalculatorLibrary.cs, cole o código no namespace CalculatorLibrary.

    Adicione também public antes da classe Calculadora para expô-la fora da biblioteca.

    Agora o CalculatorLibrary.cs deve ser semelhante ao seguinte código:

     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. O Program.cs também tem uma referência, mas um erro diz que a chamada Calculator.DoOperation não está sendo resolvida. Esse erro aparece porque CalculatorLibrary está em um namespace diferente. Para uma referência totalmente qualificada, você pode adicionar o namespace CalculatorLibrary à chamada Calculator.DoOperation:

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

    Ou você pode tentar adicionar uma diretiva using ao início do arquivo:

    using CalculatorLibrary;
    

    Adicionar a diretiva using deve permitir que você remova o namespace CalculatorLibrary do site de chamada, mas agora existe uma ambiguidade. A classe Calculator está em CalculatorLibraryou Calculator é o namespace?

    Para resolver a ambiguidade, renomeie o namespace de Calculator para CalculatorProgram em Program.cs.

    namespace CalculatorProgram
    

Referenciar bibliotecas do .NET: gravar em um log

Você pode usar a classe Trace do .NET para adicionar um log de todas as operações e gravá-lo em um arquivo de texto. A classe Trace também é útil para técnicas básicas de depuração de impressão. A classe Trace está em System.Diagnostics e usa classes System.IO como StreamWriter.

  1. Comece adicionando as diretivas using na parte superior de CalculatorLibrary.cs:

    using System.IO;
    using System.Diagnostics;
    
  2. Esse uso da classe Trace deve manter uma referência para a classe, que ela associa a um fluxo de arquivos. Esse requisito significa que a calculadora funciona melhor como objeto. Portanto, adicione um construtor no início da classe Calculator em CalculatorLibrary.cs.

    Remova também a palavra-chave static para alterar o método estático DoOperation em um método membro.

    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. Adicione a saída de log a cada cálculo. DoOperation agora seria parecida com o seguinte código:

    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. De volta ao Program.cs, um sublinhado ondulado vermelho agora sinaliza a chamada estática. Para corrigir o erro, crie uma variável calculator adicionando a seguinte linha de código pouco antes do loop while (!endApp):

    Calculator calculator = new Calculator();
    

    Modifique também o site de chamada DoOperation para referenciar o objeto chamado calculator em letras minúsculas. O código agora é uma invocação de membro, em vez de uma chamada para um método estático.

    result = calculator.DoOperation(cleanNum1, cleanNum2, op);
    
  5. Execute o aplicativo novamente. Quando terminar, clique com o botão direito do mouse no nó de projeto Calculadora e escolha Abrir Pasta no Explorador de Arquivos.

  6. No Explorador de Arquivos, navegue até a pasta de saída em bin/Debug/ e abra o arquivo calculator.log. A saída deve parecer com esta:

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

Neste ponto, o CalculatorLibrary.cs deve ser semelhante a este código:

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

O Program.cs deve ser como o seguinte código:

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

Você pode usar a classe Trace do .NET para adicionar um log de todas as operações e gravá-lo em um arquivo de texto. A classe Trace também é útil para técnicas básicas de depuração de impressão. A classe Trace está em System.Diagnostics e usa classes System.IO como StreamWriter.

  1. Comece adicionando as diretivas using na parte superior de CalculatorLibrary.cs:

    using System.Diagnostics;
    
  2. Esse uso da classe Trace deve manter uma referência para a classe, que ela associa a um fluxo de arquivos. Esse requisito significa que a calculadora funciona melhor como objeto. Portanto, adicione um construtor no início da classe Calculator em CalculatorLibrary.cs.

    Remova também a palavra-chave static para alterar o método estático DoOperation em um método membro.

    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. Adicione a saída de log a cada cálculo. DoOperation agora seria parecida com o seguinte código:

    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. De volta ao Program.cs, um sublinhado ondulado vermelho agora sinaliza a chamada estática. Para corrigir o erro, crie uma variável calculator adicionando a seguinte linha de código pouco antes do loop while (!endApp):

    Calculator calculator = new Calculator();
    

    Modifique também o site de chamada DoOperation para referenciar o objeto chamado calculator em letras minúsculas. O código agora é uma invocação de membro, em vez de uma chamada para um método estático.

    result = calculator.DoOperation(cleanNum1, cleanNum2, op);
    
  5. Execute o aplicativo novamente. Quando terminar, clique com o botão direito do mouse no nó de projeto Calculadora e escolha Abrir Pasta no Explorador de Arquivos.

  6. No Explorador de Arquivos, navegue até a pasta de saída em bin/Debug/ e abra o arquivo calculator.log. A saída deve parecer com esta:

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

Neste ponto, o CalculatorLibrary.cs deve ser semelhante a este código:

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

O Program.cs deve ser como o seguinte código:

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

Adicionar um pacote NuGet: gravar em um arquivo JSON

Para gerar operações em JSON, um formato popular e portátil para armazenar dados de objeto, você pode referenciar o pacote NuGet Newtonsoft.Json. Os pacotes NuGet são o método de distribuição principal para as bibliotecas de classes do .NET.

  1. No Gerenciador de Soluções, clique com o botão direito do mouse no nó Dependências do projeto CalculatorLibrary e escolha Gerenciar Pacotes NuGet.

    Screenshot of Manage NuGet Packages on the shortcut menu.

    Screenshot of Manage NuGet Packages on the shortcut menu.

    O Gerenciador de Pacotes NuGet será aberto.

    Screenshot of the NuGet Package Manager.

  2. Pesquise e selecione o pacote Newtonsoft.Json e selecione Instalar.

    Screenshot of Newtonsoft J SON NuGet package information in the NuGet Package Manager.

    O Visual Studio baixa o pacote e adiciona ao projeto. Uma nova entrada será exibida no nó de Referências no Gerenciador de Soluções.

    Screenshot of Newtonsoft J SON NuGet package information in the NuGet Package Manager. Se for solicitado que você aceite as alterações, selecione OK.

    O Visual Studio baixa o pacote e adiciona ao projeto. Uma nova entrada será exibida no nó Pacotes no Gerenciador de Soluções.

    Adicione uma diretiva using para Newtonsoft.Json no início de CalculatorLibrary.cs.

    using Newtonsoft.Json;
    
  3. Crie o objeto membro JsonWriter e substitua o construtor Calculator pelo seguinte código:

         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. Modifique o método DoOperation para adicionar o código JSON writer:

         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. Adicione um método para concluir a sintaxe JSON depois que o usuário terminar de inserir dados de operação.

     public void Finish()
     {
         writer.WriteEndArray();
         writer.WriteEndObject();
         writer.Close();
     }
    
  6. No final de Program.cs, antes do return;, adicione uma chamada a Finish:

             // Add call to close the JSON writer before return
             calculator.Finish();
             return;
         }
    
  7. Compile e execute o aplicativo e, depois de concluir a inserção de algumas operações, feche o aplicativo inserindo o comando n.

  8. Abra o arquivo calculatorlog.json no Explorador de Arquivos. Você deverá ver algo como o seguinte conteúdo:

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

Depurar: definição e ocorrência de um ponto de interrupção

O depurador do Visual Studio é uma ferramenta eficaz. O depurador pode percorrer seu código para encontrar o ponto exato em que há um erro de programação. Em seguida, você pode entender quais correções precisam ser feitas e pode fazer alterações temporárias para continuar executando seu aplicativo.

  1. Em Program.cs, clique na medianiz à esquerda da linha de código a seguir. Você também pode clicar na linha e selecionar F9 ou clicar com o botão direito do mouse na linha e selecionar Ponto de Interrupção>Inserir Ponto de Interrupção.

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

    O ponto vermelho exibido indica um ponto de interrupção. Você pode usar pontos de interrupção para pausar seu aplicativo e inspecionar o código. Você pode definir um ponto de interrupção em qualquer linha de código executável.

    Screenshot that shows setting a breakpoint.

  2. Compile e execute o aplicativo. Insira os seguintes valores para o cálculo:

    • Para o primeiro número, insira 8.
    • Para o segundo número, insira 0.
    • Para o operador, vamos nos divertir um pouco. Insira d.

    O aplicativo suspenderá onde você criou o ponto de interrupção, que é indicado pelo ponteiro amarelo à esquerda e pelo código realçado. O código realçado ainda não foi executado.

    Screenshot of hitting a breakpoint

    Agora, com o aplicativo suspenso, você pode inspecionar o estado do aplicativo.

Depurar: exibir variáveis

  1. No código realçado, passe o mouse sobre variáveis como cleanNum1 e op. Os valores atuais dessas variáveis (8 e d, respectivamente) são exibidos em DataTips.

    Screenshot that shows viewing a DataTip.

    Durante a depuração, verificar se as variáveis contêm os valores esperados geralmente é essencial para corrigir problemas.

  2. No painel inferior, examine a janela Locais. Se estiver fechada, selecione Depurar>Janelas>Locais para abri-la.

    A janela Locais mostra cada variável que está atualmente no escopo, juntamente com o valor e tipo.

    Screenshot of the Locals window.

    Screenshot of the Locals window.

  3. Dê uma olhada na janela Autos.

    A janela Autos é semelhante à janela Locais, mas mostra as variáveis ​​imediatamente anteriores e posteriores à linha de código atual em que seu aplicativo está pausado.

    Observação

    Se você não vir a janela Autos, selecione Depurar>Janelas>Autos para abri-la.

Em seguida, execute o código no depurador, uma instrução por vez, o que é chamado de stepping.

Depurar: passar pelo código

  1. Pressione F11 ou selecione Depurar>Intervir.

    Usando o comando Intervir, o aplicativo executa a instrução atual e avança para a próxima instrução executável, geralmente a próxima linha de código. O ponteiro amarelo à esquerda sempre indica a instrução atual.

    Screenshot of step into command

    Você acabou de intervir no método DoOperation na classe Calculator.

  2. Para obter uma análise hierárquica no fluxo do programa, examine a janela Pilha de Chamadas. Se estiver fechada, selecione Depurar>Janelas>Pilha de Chamadas para abri-la.

    Screenshot of the call stack

    Essa exibição mostra o método atual Calculator.DoOperation, indicado pelo ponteiro amarelo. A segunda linha mostra a função que chamou o método, do método Main em Program.cs.

    A janela Pilha de Chamadas mostra a ordem em que os métodos e as funções são chamados. Essa janela também fornece acesso a muitos recursos do depurador, como Ir para o Código-Fonte, no menu de atalho.

  3. Pressione F10 ou selecione Depurar>Step Over várias vezes até que o aplicativo pause na instrução switch.

    switch (op)
    {
    

    O comando Step Over é semelhante ao comando Intervir, exceto que, se a instrução atual chamar uma função, o depurador executará o código na função e não suspenderá a execução até que a função retorne. O Step Over é mais rápido do que o Intervir, se você não estiver interessado em uma função específica.

  4. Pressione F10 mais uma vez para que o aplicativo pause na linha de código a seguir.

    if (num2 != 0)
    {
    

    Esse código verifica se há um caso de divisão por zero. Se continuar, o aplicativo irá gerar uma exceção geral (um erro), mas talvez você queira tentar algo diferente, como ver o valor real retornado no console. Uma opção é usar um recurso de depurador chamado edit-and-continue para fazer alterações no código e continuar a depuração. No entanto, há um truque diferente para modificar temporariamente o fluxo de execução.

Depurar: testar uma alteração temporária

  1. Selecione o ponteiro amarelo, atualmente pausado na instrução if (num2 != 0), e arraste-o para a seguinte instrução:

    result = num1 / num2;
    

    Arrastar o ponteiro aqui faz com que o aplicativo ignore completamente a instrução if, para que você possa ver o que acontece quando você divide por zero.

  2. Pressione F10 para executar a linha de código.

  3. Se você passar o mouse sobre a variável result. Isso mostrará um valor de Infinito. No C#, Infinito é o resultado quando você divide por zero.

  4. Pressione F5 ou selecione Depurar>Continuar Depuração.

    O símbolo de infinito será exibido no console como resultado da operação matemática.

  5. Feche o aplicativo corretamente inserindo o comando n.

Conclusão do código

Este é o código completo para o arquivo CalculatorLibrary.cs, depois de concluir todas as etapas:

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

E este é o código para 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;
        }
    }
}

Este é o código completo para o arquivo CalculatorLibrary.cs, depois de concluir todas as etapas:

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

E este é o código para 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.
                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;
        }
    }
}

Próximas etapas

Parabéns por concluir este tutorial. Para saber mais, continue com o conteúdo a seguir: