Tutorial: Ampliación de la aplicación de consola de C# y depuración en Visual Studio (parte 2 de 2)

En la parte 2 de esta serie de tutoriales, profundizará un poco más en las características de compilación y depuración de Visual Studio que necesitará para el desarrollo diario. Entre estas características, se incluyen la administración de varios proyectos, la depuración y la referencia a paquetes de terceros. Ejecutará la aplicación de consola de C# que creó en la parte 1 de este tutorial y explorará algunas características del entorno de desarrollo integrado (IDE) de Visual Studio. Este tutorial es la segunda parte de una serie de tutoriales de dos partes.

En este tutorial, va a completar las siguientes tareas:

  • Agregar un segundo proyecto.
  • Hacer referencia a bibliotecas y agregar paquetes.
  • Depure el código que ha creado.
  • Inspeccionar el código completo.

Requisitos previos

Para trabajar con este artículo, puede usar cualquiera de estas aplicaciones de calculadora:

Adición de otro proyecto

El código real está formado por varios proyectos que funcionan conjuntamente para dar lugar a una solución. Puede agregar un proyecto de biblioteca de clases a la aplicación de calculadora que proporcione algunas funciones de calculadora.

En Visual Studio, use el comando de menú Archivo>Agregar>Nuevo proyecto para agregar un nuevo proyecto. También puede hacer clic con el botón derecho en la solución en el Explorador de soluciones para agregar un proyecto desde el menú contextual.

  1. En el Explorador de soluciones, haga clic con el botón derecho en el nodo de la solución y elija Agregar>Nuevo proyecto.

  2. En la ventana Agregar un nuevo proyecto, escriba biblioteca de clases en el cuadro de búsqueda. Elija la plantilla de proyecto Biblioteca de clases de C# y seleccione Siguiente.

    Screenshot of Class Library project template selection.

  3. En la pantalla Configurar el nuevo proyecto, escriba el nombre del proyecto CalculatorLibrary y, después, seleccione Siguiente.

  4. Elija .NET 3.1 cuando se le solicite. Visual Studio crea el proyecto y lo agrega a la solución.

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

  5. Cambie el nombre del archivo Class1.cs a CalculatorLibrary.cs. Para cambiar el nombre del archivo, puede hacer clic con el botón derecho en el nombre en el Explorador de soluciones y elegir Cambiar nombre, seleccionar el nombre y presionar F2 o seleccionar el nombre y volver a hacer clic para escribir.

    Un mensaje podría preguntarle si quiere cambiar el nombre de las referencias a Class1 en el archivo. No importa qué responda en este momento, ya que reemplazará el código en un paso posterior.

  6. Ahora agregue una referencia de proyecto para que el primer proyecto pueda usar las API que expone la nueva biblioteca de clases. Haga clic con el botón derecho en el nodo Dependencias del proyecto Calculator y seleccione Agregar referencia de proyecto.

    Screenshot of the Add Project Reference menu item.

    Aparecerá el cuadro de diálogo Administrador de referencias. En este cuadro de diálogo, puede agregar referencias a otros proyectos, ensamblados y DLL COM que los proyectos necesiten.

  7. En el cuadro de diálogo Administrador de referencias, active la casilla correspondiente al proyecto CalculatorLibrary y seleccione Aceptar.

    Screenshot of the Reference Manager dialog box.

    La referencia del proyecto aparece en un nodo Proyectos en el Explorador de soluciones.

    Screenshot of Solution Explorer with project reference.

  8. En Program.cs, seleccione la clase Calculator y todo su código y presione CTRL+X para cortarla. Después, en CalculatorLibrary.cs, pegue el código en el espacio de nombres CalculatorLibrary.

    Agregue también public antes de la clase Calculator para exponerla fuera de la biblioteca.

    CalculatorLibrary.cs debería tener ahora un aspecto similar al del código siguiente:

    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 también tiene una referencia, pero un error indica que la llamada a Calculator.DoOperation no se resuelve. Esto se debe a que CalculatorLibrary se encuentra en un espacio de nombres diferente. Para obtener una referencia completa, podría agregar el espacio de nombres CalculatorLibrary a la llamada a Calculator.DoOperation:

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

    También podría probar a agregar una directiva using al principio del archivo:

    using CalculatorLibrary;
    

    La adición de la directiva using debería permitirle quitar el espacio de nombres CalculatorLibrary del sitio de llamada, pero ahora hay una ambigüedad. ¿Es Calculator la clase de CalculatorLibrary, o bien es Calculator el espacio de nombres?

    Para resolver la ambigüedad, cambie el nombre del espacio de nombres de Calculator a CalculatorProgram en Program.cs.

    namespace CalculatorProgram
    
  1. En el Explorador de soluciones, haga clic con el botón derecho en el nodo de la solución y elija Agregar>Nuevo proyecto.

  2. En la ventana Agregar un nuevo proyecto, escriba biblioteca de clases en el cuadro de búsqueda. Elija la plantilla de proyecto Biblioteca de clases de C# y seleccione Siguiente.

    Screenshot of Class Library project template selection.

  3. En la pantalla Configurar el nuevo proyecto, escriba el nombre del proyecto CalculatorLibrary y, después, seleccione Siguiente.

  4. En la pantalla Información adicional, está seleccionado .NET 8.0. Seleccione Crear.

    Visual Studio crea el proyecto y lo agrega a la solución.

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

  5. Cambie el nombre del archivo Class1.cs a CalculatorLibrary.cs. Para cambiar el nombre del archivo, puede hacer clic con el botón derecho en el nombre en el Explorador de soluciones y elegir Cambiar nombre, seleccionar el nombre y presionar F2 o seleccionar el nombre y volver a hacer clic para escribir.

    Un mensaje podría preguntarle si quiere cambiar el nombre de todas las referencias a Class1 en el archivo. No importa qué responda en este momento, ya que reemplazará el código en un paso posterior.

  6. Ahora agregue una referencia de proyecto para que el primer proyecto pueda usar las API que expone la nueva biblioteca de clases. Haga clic con el botón derecho en el nodo Dependencias del proyecto Calculator y seleccione Agregar referencia de proyecto.

    Screenshot of the Add Project Reference menu item.

    Aparecerá el cuadro de diálogo Administrador de referencias. En este cuadro de diálogo, puede agregar referencias a otros proyectos, ensamblados y DLL COM que los proyectos necesiten.

  7. En el cuadro de diálogo Administrador de referencias, active la casilla correspondiente al proyecto CalculatorLibrary y seleccione Aceptar.

    Screenshot of the Reference Manager dialog box.

    La referencia del proyecto aparece en un nodo Proyectos en el Explorador de soluciones.

    Screenshot of Solution Explorer with project reference.

  8. En Program.cs, seleccione la clase Calculator y todo su código y presione CTRL+X para cortarla. Después, en CalculatorLibrary.cs, pegue el código en el espacio de nombres CalculatorLibrary.

    Agregue también public antes de la clase Calculator para exponerla fuera de la biblioteca.

    CalculatorLibrary.cs debería tener ahora un aspecto similar al del código siguiente:

     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 también tiene una referencia, pero un error indica que la llamada a Calculator.DoOperation no se resuelve. Esto se debe a que CalculatorLibrary se encuentra en un espacio de nombres diferente. Para obtener una referencia completa, podría agregar el espacio de nombres CalculatorLibrary a la llamada a Calculator.DoOperation:

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

    También podría probar a agregar una directiva using al principio del archivo:

    using CalculatorLibrary;
    

    La adición de la directiva using debería permitirle quitar el espacio de nombres CalculatorLibrary del sitio de llamada, pero ahora hay una ambigüedad. ¿Es Calculator la clase de CalculatorLibrary, o bien es Calculator el espacio de nombres?

    Para resolver la ambigüedad, cambie el nombre del espacio de nombres de Calculator a CalculatorProgram en Program.cs.

    namespace CalculatorProgram
    

Referencia a bibliotecas de .NET: escritura en un registro

Puede usar la clase Trace de .NET para agregar un registro de todas las operaciones y escribirlo en un archivo de texto. La clase Trace también es útil para las técnicas básicas de impresión de la depuración. La clase Trace está en System.Diagnostics y usa clases System.IO como StreamWriter.

  1. Empiece agregando las directivas using en la parte superior de CalculatorLibrary.cs:

    using System.IO;
    using System.Diagnostics;
    
  2. Este uso de la clase Trace debe mantener una referencia para la clase, que asocia a una secuencia de archivos. Este requisito significa que la calculadora funciona mejor como un objeto, por lo que debe agregar un constructor al principio de la clase Calculator en CalculatorLibrary.cs.

    Además, elimine la palabra clave static para cambiar el método estático DoOperation por un método de miembro.

    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. Agregue la salida del registro a cada cálculo. DoOperation debería tener ahora un aspecto similar al del código siguiente:

    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. En Program.cs, un subrayado ondulado rojo marca ahora la llamada estática. Para corregir este error, agregue la línea de código siguiente justo antes del bucle while (!endApp) para crear una variable calculator:

    Calculator calculator = new Calculator();
    

    Modifique también el sitio de llamada DoOperation para que haga referencia al objeto denominado calculator en minúsculas. El código es ahora una invocación de miembro, en lugar de una llamada a un método estático.

    result = calculator.DoOperation(cleanNum1, cleanNum2, op);
    
  5. Ejecute la aplicación de nuevo. Cuando haya terminado, haga clic con el botón derecho en el nodo de proyecto Calculator y elija Abrir la carpeta en el Explorador de archivos.

  6. En el Explorador de archivos, vaya a la carpeta de salida en bin/Debug/ y abra el archivo calculator.log. El resultado debe parecerse a este:

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

El aspecto de CalculatorLibrary.cs ahora debería ser similar al del código siguiente:

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

El aspecto de Program.cs debería ser similar al del código siguiente:

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

Puede usar la clase Trace de .NET para agregar un registro de todas las operaciones y escribirlo en un archivo de texto. La clase Trace también es útil para las técnicas básicas de impresión de la depuración. La clase Trace está en System.Diagnostics y usa clases System.IO como StreamWriter.

  1. Empiece agregando las directivas using en la parte superior de CalculatorLibrary.cs:

    using System.Diagnostics;
    
  2. Este uso de la clase Trace debe mantener una referencia para la clase, que asocia a una secuencia de archivos. Este requisito significa que la calculadora funciona mejor como un objeto, por lo que debe agregar un constructor al principio de la clase Calculator en CalculatorLibrary.cs.

    Además, elimine la palabra clave static para cambiar el método estático DoOperation por un método de miembro.

    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. Agregue la salida del registro a cada cálculo. DoOperation debería tener ahora un aspecto similar al del código siguiente:

    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. En Program.cs, un subrayado ondulado rojo marca ahora la llamada estática. Para corregir este error, agregue la línea de código siguiente justo antes del bucle while (!endApp) para crear una variable calculator:

    Calculator calculator = new Calculator();
    

    Modifique también el sitio de llamada DoOperation para que haga referencia al objeto denominado calculator en minúsculas. El código es ahora una invocación de miembro, en lugar de una llamada a un método estático.

    result = calculator.DoOperation(cleanNum1, cleanNum2, op);
    
  5. Ejecute la aplicación de nuevo. Cuando haya terminado, haga clic con el botón derecho en el nodo de proyecto Calculator y elija Abrir la carpeta en el Explorador de archivos.

  6. En el Explorador de archivos, vaya a la carpeta de salida en bin/Debug/ y abra el archivo calculator.log. El resultado debe parecerse a este:

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

El aspecto de CalculatorLibrary.cs ahora debería ser similar al del código siguiente:

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

El aspecto de Program.cs debería ser similar al del código siguiente:

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

Incorporación de un paquete NuGet: escritura en un archivo JSON

Para generar operaciones en JSON (un formato popular y portátil para almacenar datos de objeto), puede hacer referencia al paquete NuGet Newtonsoft.Json. Los paquetes NuGet son el método de distribución principal de las bibliotecas de clases de .NET.

  1. En el Explorador de soluciones, haga clic con el botón derecho en el nodo Dependencias del proyecto CalculatorLibrary y seleccione Administrar paquetes NuGet.

    Screenshot of Manage NuGet Packages on the shortcut menu.

    Screenshot of Manage NuGet Packages on the shortcut menu.

    Se abrirá el administrador de paquetes NuGet.

    Screenshot of the NuGet Package Manager.

  2. Busque y seleccione el paquete Newtonsoft.Json y seleccione Instalar.

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

    Visual Studio descarga el paquete y lo agrega al proyecto. Aparece una nueva entrada en el nodo Referencias del Explorador de soluciones.

    Screenshot of Newtonsoft J SON NuGet package information in the NuGet Package Manager. Si se le pregunta si acepta los cambios, seleccione Aceptar.

    Visual Studio descarga el paquete y lo agrega al proyecto. Aparece una nueva entrada en el nodo Paquetes del Explorador de soluciones.

    Agregue una directiva using para Newtonsoft.Json al principio de CalculatorLibrary.cs.

    using Newtonsoft.Json;
    
  3. Cree el objeto miembro JsonWriter y reemplace el constructor Calculator por el código siguiente:

         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 el método DoOperation para agregar el código writer de JSON:

         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. Agregue un método para finalizar la sintaxis de JSON una vez que el usuario haya acabado de escribir los datos de la operación.

     public void Finish()
     {
         writer.WriteEndArray();
         writer.WriteEndObject();
         writer.Close();
     }
    
  6. Al final de Program.cs, antes de return;, agregue una llamada a Finish:

             // Add call to close the JSON writer before return
             calculator.Finish();
             return;
         }
    
  7. Compile y ejecute la aplicación y, cuando acabe de escribir algunas operaciones, cierre la aplicación mediante el comando n.

  8. Abra el archivo calculatorlog.json en el Explorador de archivos. Debería ver algo parecido al contenido siguiente:

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

Depuración: establecimiento y uso de los puntos de interrupción

El depurador de Visual Studio es una herramienta eficaz. El depurador puede recorrer el código paso a paso para encontrar el punto exacto en el que hay un error de programación. De este modo, entenderá qué correcciones debe realizar y podrá introducir cambios temporales para poder seguir ejecutando la aplicación.

  1. En Program.cs, haga clic en el medianil situado a la izquierda de la siguiente línea de código. También puede hacer clic en la línea y seleccionar F9, o bien hacer clic con el botón derecho en la línea y seleccionar Punto de interrupción>Insertar punto de interrupción.

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

    El punto rojo que aparece indica un punto de interrupción. Puede usar puntos de interrupción para pausar la aplicación e inspeccionar el código. Puede establecer un punto de interrupción en cualquier línea de código ejecutable.

    Screenshot that shows setting a breakpoint.

  2. Compile y ejecute la aplicación. Escriba los siguientes valores para el cálculo:

    • Para el primer número, escriba 8.
    • Para el segundo número, escriba 0.
    • Para el operador, divirtámonos un poco: escriba d.

    La aplicación se suspende en el punto en el que creó el punto de interrupción, que se indica mediante el puntero amarillo de la izquierda y el código resaltado. El código resaltado todavía no se ha ejecutado.

    Screenshot of hitting a breakpoint

    Ahora, con la aplicación suspendida, puede inspeccionar el estado de la aplicación.

Depuración: ver variables

  1. En el código resaltado, mantenga el puntero sobre variables como cleanNum1 y op. Los valores actuales de estas variables (8 y d, respectivamente) aparecen en la información sobre datos.

    Screenshot that shows viewing a DataTip.

    Durante la depuración, suele ser fundamental para corregir los problemas comprobar si las variables contienen los valores que se esperan.

  2. En el panel inferior, examine la ventana Variables locales. Si está cerrada, seleccione Depurar>Ventanas>Variables locales para abrirla.

    En la ventana Variables locales se muestra cada variable que está actualmente en el ámbito, junto con su valor y tipo.

    Screenshot of the Locals window.

    Screenshot of the Locals window.

  3. Fíjese en la ventana Automático.

    La ventana Automático es similar a la ventana Variables locales, pero muestra las variables inmediatamente anteriores y posteriores a la línea de código actual en la que está pausada la aplicación.

    Nota

    Si no ve la ventana Automático, seleccione Depurar>Windows>Automático para abrirla.

A continuación, ejecute el código en el depurador instrucción por instrucción, lo que se denomina ejecución paso a paso.

Depuración: examinar el código

  1. Presione F11 o seleccione Depurar>Depurar paso a paso por instrucciones.

    Con el comando Depurar paso a paso por instrucciones, la aplicación ejecuta la instrucción actual y avanza a la siguiente instrucción ejecutable (normalmente la siguiente línea de código). El puntero amarillo de la izquierda siempre indica la instrucción actual.

    Screenshot of step into command

    Acaba de depurar paso a paso por instrucciones el método DoOperation de la clase Calculator.

  2. Para obtener una visión jerárquica del flujo del programa, examine la ventana Pila de llamadas. Si está cerrada, seleccione Depurar>Ventanas>Pila de llamadas para abrirla.

    Screenshot of the call stack

    Esta vista muestra el método Calculator.DoOperation actual, indicado por el puntero amarillo. La segunda fila muestra la función que llamó al método, desde el método Main en Program.cs.

    En la ventana Pila de llamadas se muestra el orden en el que se llama a los métodos y las funciones. Esta ventana también proporciona acceso a muchas características del depurador, como Ir al código fuente, en el menú contextual.

  3. Presione F10 (o seleccione Depurar>Depurar paso a paso por procedimientos) varias veces hasta que la aplicación se pause en la instrucción switch.

    switch (op)
    {
    

    El comando Depurar paso a paso por procedimientos es similar al comando Depurar paso a paso por instrucciones, salvo que si la instrucción actual llama a una función, el depurador ejecuta el código de la función y no suspende la ejecución hasta que la función vuelve. Depurar paso a paso por procedimientos es más rápido que Depurar paso a paso por instrucciones si no está interesado en una función determinada.

  4. Presione F10 una vez más para que la aplicación se pause en la siguiente línea de código.

    if (num2 != 0)
    {
    

    Este código comprueba si hay un caso de división por cero. Si la aplicación continúa, iniciará una excepción general (un error), pero podría interesarle probar algo más, como ver el valor devuelto real en la consola. Una opción consiste en usar una característica del depurador denominada Editar y continuar para realizar cambios en el código y luego seguir con la depuración. También hay un truco diferente para modificar temporalmente el flujo de ejecución.

Depuración: probar un cambio temporal

  1. Seleccione el puntero amarillo, actualmente en pausa en la instrucción if (num2 != 0), y arrástrelo a la siguiente instrucción:

    result = num1 / num2;
    

    Si arrastra el puntero hasta aquí, la aplicación omite completamente la instrucción if, por lo que puede ver lo que sucede cuando se divide por cero.

  2. Presione F10 para ejecutar la línea de código.

  3. Si mantiene el puntero sobre la variable result, se muestra un valor de infinito. En C#, infinito es el resultado de dividir por cero.

  4. Presione F5 o seleccione Depurar>Continuar depurando.

    El símbolo de infinito aparece en la consola como el resultado de la operación matemática.

  5. Cierre la aplicación correctamente mediante el comando n.

Código completo

Este es el código completo del archivo CalculatorLibrary.cs después de completar todos los pasos:

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

Y este es el código de 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 es el código completo del archivo CalculatorLibrary.cs después de completar todos los pasos:

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

Y este es el código de 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;
        }
    }
}

Pasos siguientes

Enhorabuena por completar este tutorial. Para obtener más información, continúe con el contenido siguiente: