Compartir a través de


Tutorial: Extensió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á en las características de compilación y depuración de Visual Studio que necesita para el desarrollo diario. Estas características incluyen administrar varios proyectos, depurar y hacer referencia a paquetes que no son de Microsoft.

En este tutorial, usará la aplicación de consola de C# que creó en la parte 1 de este tutorial para explorar las características del entorno de desarrollo integrado (IDE) de Visual Studio. Este tutorial es la parte 2 de una serie de tutoriales de dos partes.

En este tutorial, completará las siguientes tareas:

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

Prerrequisitos

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

Agregar otro proyecto

El código real implica proyectos que trabajan juntos en una solución. Puede agregar un proyecto de biblioteca de clases a la aplicación de calculadora que proporciona 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 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, a continuación, seleccione Siguiente.

    Captura de pantalla de la selección de la plantilla del proyecto de una biblioteca de clases.

  3. En la pantalla Configurar el nuevo proyecto , escriba el nombre del proyecto CalculatorLibrary y, a continuación, seleccione Siguiente.

  4. En la pantalla Información adicional , seleccione .NET 10.0 y, a continuación, seleccione Crear.

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

    Captura de pantalla del Explorador de soluciones con el proyecto de biblioteca de clases CalculatorLibrary agregado.

  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 bien seleccionar el nombre y volver a escribir.

    Un mensaje puede preguntar si desea cambiar el nombre de todas las referencias a Class1 en el archivo. No importa cómo responda, ya que reemplaza el código en un paso futuro.

  6. Agregue una referencia de proyecto, que permite que el primer proyecto use 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.

    Captura de pantalla del elemento de menú Agregar referencia de proyecto.

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

  7. En el cuadro de diálogo Administrador de referencias , active la casilla CalculatorLibrary y, a continuación, seleccione Aceptar.

    Captura de pantalla del cuadro de diálogo Administrador de referencias.

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

    Captura de pantalla del Explorador de soluciones con referencia del proyecto.

  8. En Program.cs, seleccione la clase Calculator y todo su código y presione Ctrl+X para cortarlo. A continuación, en CalculatorLibrary.cs, pegue el código dentro del espacio de nombres CalculatorLibrary.

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

    CalculatorLibrary.cs ahora debería parecerse al código siguiente:

     // CalculatorLibrary.cs
     namespace CalculatorLibrary
     {
         public class Calculator
         {
             public static double DoOperation(double num1, double num2, string op)
             {
                 double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.
    
                 // Use a switch statement to do the math.
                 switch (op)
                 {
                     case "a":
                         result = num1 + num2;
                         break;
                     case "s":
                         result = num1 - num2;
                         break;
                     case "m":
                         result = num1 * num2;
                         break;
                     case "d":
                         // Ask the user to enter a non-zero divisor.
                         if (num2 != 0)
                         {
                             result = num1 / num2;
                         }
                         break;
                     // Return text for an incorrect option entry.
                     default:
                         break;
                 }
                 return result;
             }
         }
     }
    
  9. Program.cs también tiene una referencia, pero un error indica que la llamada Calculator.DoOperation no se resuelve. El error se debe a que CalculatorLibrary está en un espacio de nombres diferente. Para obtener una referencia completamente calificada, podría agregar el espacio de nombres CalculatorLibrary a la llamada Calculator.DoOperation en Program.cs:

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

    O bien, podría intentar agregar una directiva using al principio del archivo Program.cs:

    // Program.cs
    using CalculatorLibrary;
    

    Agregar la directiva using debe permitirle quitar el espacio de nombres CalculatorLibrary del sitio de llamada.

    Si el código de Program.cs está en el espacio de nombres Calculator, cambie el nombre del espacio de nombres de Calculator a CalculatorProgram para quitar la ambigüedad entre el nombre de clase y el nombre del espacio de nombres.

Referencia a bibliotecas de .NET: escritura en un registro

Puede usar la clase Trace .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 Trace clase está en System.Diagnostics. Usa System.IO clases como StreamWriter.

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

    // 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. Ese requisito significa que la calculadora funciona mejor como un objeto. Agregue un constructor al principio de la Calculator clase en CalculatorLibrary.cs.

    Quite también la palabra clave static para cambiar el método estático DoOperation a un método miembro.

    // CalculatorLibrary.cs
    public Calculator()
       {
           StreamWriter logFile = File.CreateText("calculator.log");
           Trace.Listeners.Add(new TextWriterTraceListener(logFile));
           Trace.AutoFlush = true;
           Trace.WriteLine("Starting Calculator Log");
           Trace.WriteLine(String.Format("Started {0}", System.DateTime.Now.ToString()));
       }
    
    public double DoOperation(double num1, double num2, string op)
       {
    
  3. Agregue la salida del registro a cada cálculo. DoOperation ahora debería tener un aspecto similar al código siguiente:

    // CalculatorLibrary.cs
    public double DoOperation(double num1, double num2, string op)
    {
         double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.
    
         // Use a switch statement to do the math.
         switch (op)
         {
             case "a":
                 result = num1 + num2;
                 Trace.WriteLine(String.Format("{0} + {1} = {2}", num1, num2, result));
                 break;
             case "s":
                 result = num1 - num2;
                 Trace.WriteLine(String.Format("{0} - {1} = {2}", num1, num2, result));
                 break;
             case "m":
                 result = num1 * num2;
                 Trace.WriteLine(String.Format("{0} * {1} = {2}", num1, num2, result));
                 break;
             case "d":
                 // Ask the user to enter a non-zero divisor.
                 if (num2 != 0)
                 {
                     result = num1 / num2;
                     Trace.WriteLine(String.Format("{0} / {1} = {2}", num1, num2, result));
                 }
                     break;
             // Return text for an incorrect option entry.
             default:
                 break;
         }
         return result;
     }
    
  4. En Program.cs, un subrayado ondulado rojo marca ahora la llamada estática. Para corregir el error, cree una variable calculator agregando la siguiente línea de código justo antes del bucle while (!endApp):

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

    Modifique también el sitio de llamada de DoOperation para hacer 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.

    // Program.cs
    result = calculator.DoOperation(cleanNum1, cleanNum2, op);
    
  5. Vuelva a ejecutar la aplicación. 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. La salida debe tener un aspecto similar al siguiente:

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

En este momento, CalculatorLibrary.cs deben parecerse a este código:

// CalculatorLibrary.cs
using System.Diagnostics;

namespace CalculatorLibrary
{
    public class Calculator
    {

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

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

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

Program.cs debe tener un aspecto similar al código siguiente:

// Program.cs
using CalculatorLibrary;

namespace CalculatorProgram
{

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

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

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

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

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

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

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

                string? op = Console.ReadLine();

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

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

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

Agregar un paquete NuGet: escribir 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 para las bibliotecas de clases de .NET.

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

    Captura de pantalla de Administrar paquetes NuGet en el menú contextual.

    Se abre el Administrador de paquetes NuGet.

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

    Captura de pantalla de la información del paquete NuGet Json de Newtonsoft en el Administrador de paquetes NuGet.

    Si se le pide que acepte 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.

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

         // CalculatorLibrary.cs
         JsonWriter writer;
    
         public Calculator()
         {
             StreamWriter logFile = File.CreateText("calculatorlog.json");
             logFile.AutoFlush = true;
             writer = new JsonTextWriter(logFile);
             writer.Formatting = Formatting.Indented;
             writer.WriteStartObject();
             writer.WritePropertyName("Operations");
             writer.WriteStartArray();
         }
    
  4. Modifique el método DoOperation para agregar el código de writer JSON:

         // CalculatorLibrary.cs
         public double DoOperation(double num1, double num2, string op)
         {
             double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.
             writer.WriteStartObject();
             writer.WritePropertyName("Operand1");
             writer.WriteValue(num1);
             writer.WritePropertyName("Operand2");
             writer.WriteValue(num2);
             writer.WritePropertyName("Operation");
             // Use a switch statement to do the math.
             switch (op)
             {
                 case "a":
                     result = num1 + num2;
                     writer.WriteValue("Add");
                     break;
                 case "s":
                     result = num1 - num2;
                     writer.WriteValue("Subtract");
                     break;
                 case "m":
                     result = num1 * num2;
                     writer.WriteValue("Multiply");
                     break;
                 case "d":
                     // Ask the user to enter a non-zero divisor.
                     if (num2 != 0)
                     {
                         result = num1 / num2;
                     }
                     writer.WriteValue("Divide");
                     break;
                 // Return text for an incorrect option entry.
                 default:
                     break;
             }
             writer.WritePropertyName("Result");
             writer.WriteValue(result);
             writer.WriteEndObject();
    
             return result;
         }
    
  5. Agregue un método para finalizar la sintaxis JSON después de que el usuario haya terminado de escribir los datos de la operación.

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

         // Program.cs
             // Add call to close the JSON writer before return
             calculator.Finish();
             return;
         }
    
  7. Compile y ejecute la aplicación. Después de realizar algunas operaciones, cierre la aplicación escribiendo el comando n .

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

    {
     "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 para encontrar el punto donde hay un error de programación. A continuación, puede comprender qué correcciones necesita realizar y realizar cambios temporales para que pueda seguir ejecutando la aplicación.

  1. En Program.cs, en el margen de la izquierda, seleccione la siguiente línea de código.

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

    También puede seleccionar dentro de la línea y seleccionar F9, o bien hacer clic con el botón derecho en la línea y seleccionar Insertar>punto de interrupción.

    El punto rojo que aparece indica un punto de interrupción. Puedes 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.

    Captura de pantalla que muestra cómo establecer un punto de interrupción.

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

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

    La aplicación se suspende donde creó el punto de interrupción. El puntero amarillo de la izquierda y el código resaltado indican la línea suspendida. El código resaltado aún no se ha ejecutado.

    Captura de pantalla que muestra cómo alcanzar un punto de interrupción.

    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 Información sobre datos.

    Captura de pantalla que muestra la visualización de un DataTip.

    Al depurar código, comprobar si las variables contienen los valores que se espera a menudo es crucial para corregir problemas.

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

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

    Captura de pantalla de la ventana Variables locales.

  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 código en el depurador una instrucción cada vez, que se denomina paso a paso.

Depuración: examinar el código

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

    Con el comando Step Into, 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.

    Captura de pantalla del comando paso a paso.

    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.

    Captura de pantalla de la ventana pila de llamadas.

    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, desde su 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.

    // CalculatorLibrary.cs
    switch (op)
    {
    

    El comando Paso a paso por encima es similar al comando Paso a paso en. Para el comando "Step Over", si la instrucción actual llama a una función, el depurador ejecuta el código dentro de la función. No suspende la ejecución hasta que se devuelva la función. 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 detenga en la siguiente línea de código.

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

    Este código comprueba si hay un caso de división por cero. Si la aplicación continúa, produce una excepción general (un error), pero es posible que quiera probar otra cosa, como ver el valor devuelto real en la consola. Una opción es usar una característica del depurador llamada editar y continuar para realizar cambios en el código y, a continuación, continuar con la depuración. Sin embargo, 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:

    // CalculatorLibrary.cs
    result = num1 / num2;
    

    Arrastrar el puntero aquí hace que la aplicación omita 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 coloca el cursor sobre la variable result, muestra un valor de Infinito. En C#, Infinity es el resultado cuando se divide por cero.

  4. Presione F5, o seleccione Depurar>Continuar depurando.

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

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

Código completado

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

// CalculatorLibrary.cs
using Newtonsoft.Json;

namespace CalculatorLibrary
{
    public class Calculator
    {

        JsonWriter writer;

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

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

            return result;
        }

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

Y este es el código de Program.cs:

// Program.cs
using CalculatorLibrary;

namespace CalculatorProgram
{

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

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

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

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

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

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

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

                string? op = Console.ReadLine();

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

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

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

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