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:
- La aplicación de consola de calculadora de la parte 1 de este tutorial.
- La aplicación de calculadora de C# del repositorio vs-tutorial-samples. Para empezar, abra la aplicación desde el repositorio.
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.
En el Explorador de soluciones, haga clic con el botón derecho en el nodo de la solución y elija Agregar>Nuevo proyecto.
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.
En la pantalla Configurar el nuevo proyecto, escriba el nombre del proyecto CalculatorLibrary y, después, seleccione Siguiente.
Elija .NET 3.1 cuando se le solicite. Visual Studio crea el proyecto y lo agrega a la solución.
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.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.
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.
En el cuadro de diálogo Administrador de referencias, active la casilla correspondiente al proyecto CalculatorLibrary y seleccione Aceptar.
La referencia del proyecto aparece en un nodo Proyectos en el Explorador de soluciones.
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 nombresCalculatorLibrary
.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; } } }
Program.cs también tiene una referencia, pero un error indica que la llamada a
Calculator.DoOperation
no se resuelve. Esto se debe a queCalculatorLibrary
se encuentra en un espacio de nombres diferente. Para obtener una referencia completa, podría agregar el espacio de nombresCalculatorLibrary
a la llamada aCalculator.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 nombresCalculatorLibrary
del sitio de llamada, pero ahora hay una ambigüedad. ¿EsCalculator
la clase deCalculatorLibrary
, o bien esCalculator
el espacio de nombres?Para resolver la ambigüedad, cambie el nombre del espacio de nombres de
Calculator
aCalculatorProgram
en Program.cs.namespace CalculatorProgram
En el Explorador de soluciones, haga clic con el botón derecho en el nodo de la solución y elija Agregar>Nuevo proyecto.
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.
En la pantalla Configurar el nuevo proyecto, escriba el nombre del proyecto CalculatorLibrary y, después, seleccione Siguiente.
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.
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.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.
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.
En el cuadro de diálogo Administrador de referencias, active la casilla correspondiente al proyecto CalculatorLibrary y seleccione Aceptar.
La referencia del proyecto aparece en un nodo Proyectos en el Explorador de soluciones.
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 nombresCalculatorLibrary
.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; } } }
Program.cs también tiene una referencia, pero un error indica que la llamada a
Calculator.DoOperation
no se resuelve. Esto se debe a queCalculatorLibrary
se encuentra en un espacio de nombres diferente. Para obtener una referencia completa, podría agregar el espacio de nombresCalculatorLibrary
a la llamada aCalculator.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 nombresCalculatorLibrary
del sitio de llamada, pero ahora hay una ambigüedad. ¿EsCalculator
la clase deCalculatorLibrary
, o bien esCalculator
el espacio de nombres?Para resolver la ambigüedad, cambie el nombre del espacio de nombres de
Calculator
aCalculatorProgram
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
.
Empiece agregando las directivas
using
en la parte superior de CalculatorLibrary.cs:using System.IO; using System.Diagnostics;
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 claseCalculator
en CalculatorLibrary.cs.Además, elimine la palabra clave
static
para cambiar el método estáticoDoOperation
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) {
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; }
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 variablecalculator
:Calculator calculator = new Calculator();
Modifique también el sitio de llamada
DoOperation
para que haga referencia al objeto denominadocalculator
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);
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.
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
.
Empiece agregando las directivas
using
en la parte superior de CalculatorLibrary.cs:using System.Diagnostics;
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 claseCalculator
en CalculatorLibrary.cs.Además, elimine la palabra clave
static
para cambiar el método estáticoDoOperation
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) {
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; }
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 variablecalculator
:Calculator calculator = new Calculator();
Modifique también el sitio de llamada
DoOperation
para que haga referencia al objeto denominadocalculator
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);
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.
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.
En el Explorador de soluciones, haga clic con el botón derecho en el nodo Dependencias del proyecto CalculatorLibrary y seleccione Administrar paquetes NuGet.
Se abrirá el administrador de paquetes NuGet.
Busque y seleccione el paquete Newtonsoft.Json y seleccione Instalar.
Visual Studio descarga el paquete y lo agrega al proyecto. Aparece una nueva entrada en el nodo Referencias del Explorador de soluciones.
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
paraNewtonsoft.Json
al principio de CalculatorLibrary.cs.using Newtonsoft.Json;
Cree el objeto miembro
JsonWriter
y reemplace el constructorCalculator
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(); }
Modifique el método
DoOperation
para agregar el códigowriter
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; }
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(); }
Al final de Program.cs, antes de
return;
, agregue una llamada aFinish
:// Add call to close the JSON writer before return calculator.Finish(); return; }
Compile y ejecute la aplicación y, cuando acabe de escribir algunas operaciones, cierre la aplicación mediante el comando n.
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.
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.
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.
Ahora, con la aplicación suspendida, puede inspeccionar el estado de la aplicación.
Depuración: ver variables
En el código resaltado, mantenga el puntero sobre variables como
cleanNum1
yop
. Los valores actuales de estas variables (8
yd
, respectivamente) aparecen en la información sobre datos.Durante la depuración, suele ser fundamental para corregir los problemas comprobar si las variables contienen los valores que se esperan.
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.
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
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.
Acaba de depurar paso a paso por instrucciones el método
DoOperation
de la claseCalculator
.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.
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étodoMain
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.
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.
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
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.Presione F10 para ejecutar la línea de código.
Si mantiene el puntero sobre la variable
result
, se muestra un valor de infinito. En C#, infinito es el resultado de dividir por cero.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.
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:
- Continuar con más tutoriales de C#
- Inicio rápido: Creación de una aplicación web ASP.NET Core
- Información sobre cómo depurar código de C# con Visual Studio
- Tutorial sobre cómo crear y ejecutar pruebas unitarias
- Ejecución de un programa de C#
- Información sobre IntelliSense para C#
- Información general sobre Continuar con el IDE de Visual Studio
- Registro y seguimiento