Självstudie: Utöka C#-konsolappen och felsöka i Visual Studio (del 2 av 2)
I del 2 i den här självstudieserien går du lite djupare in i visual studio-funktionerna för att skapa och felsöka de funktioner som du behöver för den dagliga utvecklingen. Dessa funktioner omfattar att hantera flera projekt, felsöka och referera till paket från tredje part. Du kör C#-konsolappen som du skapade i del 1 i den här självstudienoch utforskar några funktioner i Visual Studio Integrated Development Environment (IDE). Den här självstudien är del 2 i en självstudieserie i två delar.
I den här självstudien utför du följande uppgifter:
- Lägg till ett andra projekt.
- Referensbibliotek och lägg till paket.
- Felsök koden.
- Kontrollera den färdiga koden.
Förutsättningar
Om du vill gå igenom den här artikeln kan du använda någon av dessa kalkylatorappar:
- kalkylatorkonsolappen från del 1 i den här handledningen.
- C#-kalkylatorappen i vs-tutorial-samples-lagringsplatsen . Kom igång genom att öppna appen från lagringsplatsen.
Lägg till ett annat projekt
Verklig kod omfattar projekt som arbetar tillsammans i en lösning. Du kan lägga till ett klassbiblioteksprojekt i kalkylatorappen som innehåller vissa kalkylatorfunktioner.
I Visual Studio använder du menykommandot File>Add>New Project för att lägga till ett nytt projekt. Du kan också högerklicka på lösningen i Solution Explorer för att lägga till ett projekt från snabbmenyn.
I Solution Explorerhögerklickar du på lösningsnoden och väljer Lägg till>Nytt projekt.
I fönstret Lägg till ett nytt projekt skriver du klassbiblioteket i sökrutan. Välj projektmallen C# klassbibliotek och välj därefter Nästa.
På skärmen Konfigurera ditt nya projekt skriver du projektnamnet CalculatorLibraryoch väljer sedan Nästa.
Välj .NET 3.1 när du tillfrågas. Visual Studio skapar det nya projektet och lägger till det i lösningen.
Byt namn på filen Class1.cs till CalculatorLibrary.cs. Om du vill byta namn på filen kan du högerklicka på namnet i Solution Explorer och välja Byt namn, välj namnet och tryck på F2eller välj namnet och välj igen för att skriva.
Ett meddelande kan fråga om du vill byta namn på referenser till
Class1
i filen. Det spelar ingen roll hur du svarar, eftersom du ersätter koden i ett framtida steg.Lägg nu till en projektreferens så att det första projektet kan använda API:er som det nya klassbiblioteket exponerar. Högerklicka på noden Beroenden i projektet Calculator och välj Lägg till projektreferens.
Dialogrutan Reference Manager visas. I den här dialogrutan kan du lägga till referenser till andra projekt, sammansättningar och COM-DLL:er som dina projekt behöver.
I dialogrutan Reference Manager markerar du kryssrutan för projektet CalculatorLibrary och väljer sedan OK.
Projektreferensen visas under en nod Projects i Solution Explorer.
I Program.csväljer du klassen
Calculator
och all dess kod och trycker på Ctrl+X för att klippa ut den. I CalculatorLibrary.csklistrar du sedan in koden iCalculatorLibrary
namnområdet.Lägg också till
public
före klassen Kalkylator för att exponera den utanför biblioteket.CalculatorLibrary.cs bör nu likna följande kod:
// CalculatorLibrary.cs using System; namespace CalculatorLibrary { public class Calculator { public static double DoOperation(double num1, double num2, string op) { double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error. // Use a switch statement to do the math. switch (op) { case "a": result = num1 + num2; break; case "s": result = num1 - num2; break; case "m": result = num1 * num2; break; case "d": // Ask the user to enter a non-zero divisor. if (num2 != 0) { result = num1 / num2; } break; // Return text for an incorrect option entry. default: break; } return result; } } }
Program.cs har också en referens, men ett fel säger att
Calculator.DoOperation
-anropet inte löser problemet. Felet beror på attCalculatorLibrary
finns i ett annat namnområde. För en fullständigt kvalificerad referens kan du lägga tillCalculatorLibrary
-namnområdet iCalculator.DoOperation
-anropet i Program.cs:// Program.cs result = CalculatorLibrary.Calculator.DoOperation(cleanNum1, cleanNum2, op);
Du kan också prova att lägga till ett
using
-direktiv i början av Program.cs-filen:// Program.cs using CalculatorLibrary;
Genom att lägga till
using
-direktivet kan du ta bortCalculatorLibrary
namnområdet från anropswebbplatsen, men nu finns det en tvetydighet. ÄrCalculator
klassen iCalculatorLibrary
, eller ärCalculator
namnområdet?Lös tvetydigheten genom att byta namn på namnområdet från
Calculator
tillCalculatorProgram
i Program.cs.// Program.cs namespace CalculatorProgram
I Solution Explorerhögerklickar du på lösningsnoden och väljer Lägg till>Nytt projekt.
I fönstret Lägg till ett nytt projekt skriver du klassbiblioteket i sökrutan. Välj projektmallen C# klassbibliotek och välj därefter Nästa.
På skärmen Konfigurera ditt nya projekt skriver du projektnamnet CalculatorLibraryoch väljer sedan Nästa.
På skärmen Ytterligare information väljs .NET 8.0. Välj Skapa.
Visual Studio skapar det nya projektet och lägger till det i lösningen.
Byt namn på filen Class1.cs till CalculatorLibrary.cs. Om du vill byta namn på filen kan du högerklicka på namnet i Solution Explorer och välja Byt namn, välj namnet och tryck på F2eller välj namnet och välj igen för att skriva.
Ett meddelande kan fråga om du vill byta namn på alla referenser till
Class1
i filen. Det spelar ingen roll hur du svarar, eftersom du ersätter koden i ett framtida steg.Lägg nu till en projektreferens så att det första projektet kan använda API:er som det nya klassbiblioteket exponerar. Högerklicka på noden Beroenden i projektet Calculator och välj Lägg till projektreferens.
Dialogrutan Reference Manager visas. I den här dialogrutan kan du lägga till referenser till andra projekt, sammansättningar och COM-DLL:er som dina projekt behöver.
I dialogrutan Reference Manager markerar du kryssrutan för projektet CalculatorLibrary och väljer sedan OK.
Projektreferensen visas under en nod Projects i Solution Explorer.
I Program.csväljer du klassen
Calculator
och all dess kod och trycker på Ctrl+X för att klippa ut den. I CalculatorLibrary.csklistrar du sedan in koden iCalculatorLibrary
namnområdet.Lägg också till
public
före klassen Kalkylator för att exponera den utanför biblioteket.CalculatorLibrary.cs bör nu likna följande kod:
// 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; } } }
Program.cs har också en referens, men ett fel säger att
Calculator.DoOperation
-anropet inte löser problemet. Felet beror på attCalculatorLibrary
finns i ett annat namnområde. För en fullständigt kvalificerad referens kan du lägga tillCalculatorLibrary
-namnområdet iCalculator.DoOperation
-anropet i Program.cs:// Program.cs result = CalculatorLibrary.Calculator.DoOperation(cleanNum1, cleanNum2, op);
Du kan också prova att lägga till ett
using
-direktiv i början av Program.cs-filen:// Program.cs using CalculatorLibrary;
Genom att lägga till
using
-direktivet kan du ta bortCalculatorLibrary
-namnområdet från anropswebbplatsen.Om din
Program.cs
kod finns i namnområdetCalculator
byter du namn på namnområdet frånCalculator
tillCalculatorProgram
för att ta bort tvetydighet mellan klassnamn och namnområdesnamn.
Referensbibliotek för .NET: Skriv till en logg
Du kan använda klassen .NET Trace för att lägga till en logg över alla åtgärder och skriva den till en textfil. Klassen Trace
är också användbar för grundläggande utskriftsfelsökningstekniker. Klassen Trace
finns i System.Diagnostics
och använder System.IO
klasser som StreamWriter
.
Börja med att lägga till
using
direktiv överst i CalculatorLibrary.cs:// CalculatorLibrary.cs using System.IO; using System.Diagnostics;
Den här användningen av klassen
Trace
måste innehålla en referens för klassen, som den associerar med en filström. Det kravet innebär att kalkylatorn fungerar bättre som ett objekt, så lägg till en konstruktor i början av klassenCalculator
i CalculatorLibrary.cs.Ta också bort nyckelordet
static
för att ändra metoden staticDoOperation
till en medlemsmetod.// 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) {
Lägg till loggutdata i varje beräkning.
DoOperation
bör nu se ut som följande kod:// 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; }
Tillbaka i Program.csflaggar nu en röd vågig understrykning det statiska anropet. Åtgärda felet genom att skapa en
calculator
variabel genom att lägga till följande kodrad precis förewhile (!endApp)
-loopen:// Program.cs Calculator calculator = new Calculator();
Ändra även
DoOperation
-anropet så att det refererar till objektet med namnetcalculator
i gemener. Koden är nu ett medlemsanrop i stället för ett anrop till en statisk metod.// Program.cs result = calculator.DoOperation(cleanNum1, cleanNum2, op);
Kör appen igen. När du är klar högerklickar du på projektnoden Calculator och väljer Öppna mapp i Utforskaren.
I Utforskaren navigerar du till utdatamappen under bin/Debug/net8.0 (eller vilken .NET-version du använder) och öppnar filen calculator.log. Utdata bör se ut ungefär så här:
Starting Calculator Log Started 7/9/2020 1:58:19 PM 1 + 2 = 3 3 * 3 = 9
Nu bör CalculatorLibrary.cs likna den här koden:
// CalculatorLibrary.cs
using System;
using System.IO;
using System.Diagnostics;
namespace CalculatorLibrary
{
public class Calculator
{
public Calculator()
{
StreamWriter logFile = File.CreateText("calculator.log");
Trace.Listeners.Add(new TextWriterTraceListener(logFile));
Trace.AutoFlush = true;
Trace.WriteLine("Starting Calculator Log");
Trace.WriteLine(String.Format("Started {0}", System.DateTime.Now.ToString()));
}
public double DoOperation(double num1, double num2, string op)
{
double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.
// Use a switch statement to do the math.
switch (op)
{
case "a":
result = num1 + num2;
Trace.WriteLine(String.Format("{0} + {1} = {2}", num1, num2, result));
break;
case "s":
result = num1 - num2;
Trace.WriteLine(String.Format("{0} - {1} = {2}", num1, num2, result));
break;
case "m":
result = num1 * num2;
Trace.WriteLine(String.Format("{0} * {1} = {2}", num1, num2, result));
break;
case "d":
// Ask the user to enter a non-zero divisor.
if (num2 != 0)
{
result = num1 / num2;
Trace.WriteLine(String.Format("{0} / {1} = {2}", num1, num2, result));
}
break;
// Return text for an incorrect option entry.
default:
break;
}
return result;
}
}
}
Program.cs bör se ut som följande kod:
// Program.cs
using System;
using CalculatorLibrary;
namespace CalculatorProgram
{
class Program
{
static void Main(string[] args)
{
bool endApp = false;
// Display title as the C# console calculator app.
Console.WriteLine("Console Calculator in C#\r");
Console.WriteLine("------------------------\n");
Calculator calculator = new Calculator();
while (!endApp)
{
// Declare variables and set to empty.
string numInput1 = "";
string numInput2 = "";
double result = 0;
// Ask the user to type the first number.
Console.Write("Type a number, and then press Enter: ");
numInput1 = Console.ReadLine();
double cleanNum1 = 0;
while (!double.TryParse(numInput1, out cleanNum1))
{
Console.Write("This is not valid input. Please enter an integer value: ");
numInput1 = Console.ReadLine();
}
// Ask the user to type the second number.
Console.Write("Type another number, and then press Enter: ");
numInput2 = Console.ReadLine();
double cleanNum2 = 0;
while (!double.TryParse(numInput2, out cleanNum2))
{
Console.Write("This is not valid input. Please enter an integer value: ");
numInput2 = Console.ReadLine();
}
// Ask the user to choose an operator.
Console.WriteLine("Choose an operator from the following list:");
Console.WriteLine("\ta - Add");
Console.WriteLine("\ts - Subtract");
Console.WriteLine("\tm - Multiply");
Console.WriteLine("\td - Divide");
Console.Write("Your option? ");
string op = Console.ReadLine();
try
{
result = calculator.DoOperation(cleanNum1, cleanNum2, op);
if (double.IsNaN(result))
{
Console.WriteLine("This operation will result in a mathematical error.\n");
}
else Console.WriteLine("Your result: {0:0.##}\n", result);
}
catch (Exception e)
{
Console.WriteLine("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message);
}
Console.WriteLine("------------------------\n");
// Wait for the user to respond before closing.
Console.Write("Press 'n' and Enter to close the app, or press any other key and Enter to continue: ");
if (Console.ReadLine() == "n") endApp = true;
Console.WriteLine("\n"); // Friendly linespacing.
}
return;
}
}
}
Du kan använda klassen .NET Trace för att lägga till en logg över alla åtgärder och skriva den till en textfil. Klassen Trace
är också användbar för grundläggande utskriftsfelsökningstekniker. Klassen Trace
finns i System.Diagnostics
och använder System.IO
klasser som StreamWriter
.
Börja med att lägga till
using
direktiv överst i CalculatorLibrary.cs:// CalculatorLibrary.cs using System.Diagnostics;
Den här användningen av klassen
Trace
måste innehålla en referens för klassen, som den associerar med en filström. Det kravet innebär att kalkylatorn fungerar bättre som ett objekt, så lägg till en konstruktor i början av klassenCalculator
i CalculatorLibrary.cs.Ta också bort nyckelordet
static
för att ändra metoden staticDoOperation
till en medlemsmetod.// 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) {
Lägg till loggutdata i varje beräkning.
DoOperation
bör nu se ut som följande kod:// 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; }
Tillbaka i Program.csflaggar nu en röd vågig understrykning det statiska anropet. Åtgärda felet genom att skapa en
calculator
variabel genom att lägga till följande kodrad precis förewhile (!endApp)
-loopen:// Program.cs Calculator calculator = new Calculator();
Ändra även
DoOperation
-anropet så att det refererar till objektet med namnetcalculator
i gemener. Koden är nu ett medlemsanrop i stället för ett anrop till en statisk metod.// Program.cs result = calculator.DoOperation(cleanNum1, cleanNum2, op);
Kör appen igen. När du är klar högerklickar du på projektnoden Calculator och väljer Öppna mapp i Utforskaren.
I Utforskaren går du till utdatamappen under bin/Debug/och öppnar filen calculator.log. Utdata bör se ut ungefär så här:
Starting Calculator Log Started 7/9/2020 1:58:19 PM 1 + 2 = 3 3 * 3 = 9
Nu bör CalculatorLibrary.cs likna den här koden:
// 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 bör se ut som följande kod:
// 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;
}
}
}
Lägg till ett NuGet-paket: Skriv till en JSON-fil
För utdataåtgärder i JSON, ett populärt och portabelt format för lagring av objektdata, kan du referera till Newtonsoft.Json- NuGet-paketet. NuGet-paket är den primära distributionsmetoden för .NET-klassbibliotek.
I Solution Explorerhögerklickar du på noden Beroenden för projektet CalculatorLibrary och väljer Hantera NuGet-paket.
NuGet Package Manager öppnas.
Sök efter och välj Newtonsoft.Json--paketet och välj Installera.
Visual Studio laddar ned paketet och lägger till det i projektet. Ett nytt element visas i noden Referenser i Solution Explorer.
Om du uppmanas att godkänna ändringar väljer du OK.
Visual Studio laddar ned paketet och lägger till det i projektet. En ny post i en Packages-nod visas i Solution Explorer.
Lägg till ett
using
direktiv förNewtonsoft.Json
i början av CalculatorLibrary.cs.// CalculatorLibrary.cs using Newtonsoft.Json;
Skapa
JsonWriter
medlemsobjektet och ersättCalculator
konstruktorn med följande kod:// 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(); }
Ändra
DoOperation
-metoden för att lägga till JSON-writer
-koden:// 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; }
Lägg till en metod för att slutföra JSON-syntaxen när användaren har angett åtgärdsdata.
// CalculatorLibrary.cs public void Finish() { writer.WriteEndArray(); writer.WriteEndObject(); writer.Close(); }
I slutet av Program.cslägger du till ett anrop till
return;
innanFinish
:// Program.cs // Add call to close the JSON writer before return calculator.Finish(); return; }
Skapa och kör appen, och när du har angett några åtgärder stänger du appen genom att ange kommandot n.
Öppna filen calculatorlog.json i Utforskaren. Du bör se något som liknar följande innehåll:
{ "Operations": [ { "Operand1": 2.0, "Operand2": 3.0, "Operation": "Add", "Result": 5.0 }, { "Operand1": 3.0, "Operand2": 4.0, "Operation": "Multiply", "Result": 12.0 } ] }
Felsökning: Ange och träffa en brytpunkt
Visual Studio-felsökningsprogrammet är ett kraftfullt verktyg. Felsökningsprogrammet kan gå igenom koden för att hitta den exakta punkten där det finns ett programmeringsfel. Sedan kan du förstå vilka korrigeringar du behöver göra och göra tillfälliga ändringar så att du kan fortsätta köra appen.
I Program.csklickar du i marginalen till vänster om följande kodrad. Du kan också klicka på raden och välja F9, eller högerklicka på raden och välja Brytpunkt>Infoga brytpunkt.
// Program.cs result = calculator.DoOperation(cleanNum1, cleanNum2, op);
Den röda punkt som visas anger en brytpunkt. Du kan använda brytpunkter för att pausa din app och inspektera kod. Du kan ange en brytpunkt på valfri körbar kodrad.
Skapa och kör appen. Ange följande värden för beräkningen:
- För det första talet anger du 8.
- För det andra talet anger du 0.
- För operatören, låt oss ha lite kul. Ange d.
Appen pausar där du skapade brytpunkten, vilket indikeras av den gula pekaren till vänster och den markerade koden. Den markerade koden har ännu inte körts.
Nu när appen har inaktiverats kan du kontrollera programtillståndet.
Felsökning: Visa variabler
Hovra över variabler som
cleanNum1
ochop
i den markerade koden. Aktuella värden för dessa variabler,8
respektived
, visas i Datatips.Vid felsökning är det ofta viktigt att kontrollera om variabler innehåller de värden som du förväntar dig för att åtgärda problem.
I den nedre rutan tittar du på fönstret Locals. Om den är stängd väljer du Felsök>Windows>Locals för att öppna den.
Fönstret Locals visar varje variabel som för närvarande finns i omfånget, tillsammans med dess värde och typ.
Titta på fönstret Autos.
Fönstret Autos liknar fönstret Locals, men visar variablerna direkt före och följer den aktuella kodraden där appen har pausats.
Not
Om du inte ser fönstret Autos, välj Felsöka>Windows>Autos för att öppna det.
Kör sedan kod i felsökaren ett steg i taget, vilket kallas stegning.
Felsökning: Stega igenom kod
Tryck på F11eller välj Felsök>Steg in i.
Med kommandot Step Into kör appen den aktuella instruktionen och går vidare till nästa körbara instruktion, vanligtvis nästa kodrad. Den gula pekaren till vänster anger alltid den aktuella instruktionen.
Du har precis gått in i metoden
DoOperation
i klassenCalculator
.Om du vill få en hierarkisk vy över programflödet, titta i fönstret Anropsstack. Om den är stängd väljer du Felsök>Windows>Anropsstack för att öppna den.
Den här vyn visar den aktuella metoden
Calculator.DoOperation
, som anges av den gula pekaren. Den andra raden visar funktionen som anropade metoden från metodenMain
i Program.cs.Fönstret Call Stack visar i vilken ordning metoder och funktioner anropas. Det här fönstret ger också åtkomst till många felsökningsfunktioner, till exempel Gå till källkod, från snabbmenyn.
Tryck på F10eller välj Felsöka>Steg överflera gånger tills appen pausar
switch
-instruktionen.// CalculatorLibrary.cs switch (op) {
Kommandot Step Over liknar kommandot Step Into, förutom att om den aktuella instruktionen anropar en funktion kör felsökningsprogrammet koden i funktionen och pausar inte körningen förrän funktionen returneras. Step Over är snabbare än Step Into om du inte är intresserad av en viss funktion.
Tryck på F10 en gång till så att appen pausar på följande kodrad.
// CalculatorLibrary.cs if (num2 != 0) {
Den här koden kontrollerar ett fall av division med noll. Om appen fortsätter genererar den ett allmänt undantag (ett fel), men du kanske vill prova något annat, som att visa det faktiska returnerade värdet i konsolen. Ett alternativ är att använda en felsökningsfunktion med namnet redigera och fortsätt för att göra ändringar i koden och sedan fortsätta felsökningen. Det finns dock ett annat trick för att tillfälligt ändra exekveringsflödet.
Felsökning: Testa en tillfällig ändring
Välj den gula pekaren, som för närvarande är pausad på
if (num2 != 0)
-instruktionen, och dra den till följande instruktion:// CalculatorLibrary.cs result = num1 / num2;
Om du drar pekaren här hoppar appen helt över
if
-instruktionen, så att du kan se vad som händer när du delar med noll.Tryck på F10 för att köra kodraden.
Om du hovrar över variabeln
result
, visas värdet Infinity. I C#är Infinity resultatet när du delar med noll.Tryck på F5eller välj Felsök>Fortsätt felsöka.
Oändlighetssymbolen visas i konsolen som ett resultat av matematisk åtgärd.
Stäng appen korrekt genom att ange kommandot n.
Koden har slutförts
Här är den fullständiga koden för CalculatorLibrary.cs-filen när du har slutfört alla steg:
// CalculatorLibrary.cs
using System;
using System.IO;
using Newtonsoft.Json;
namespace CalculatorLibrary
{
public class Calculator
{
JsonWriter writer;
public Calculator()
{
StreamWriter logFile = File.CreateText("calculatorlog.json");
logFile.AutoFlush = true;
writer = new JsonTextWriter(logFile);
writer.Formatting = Formatting.Indented;
writer.WriteStartObject();
writer.WritePropertyName("Operations");
writer.WriteStartArray();
}
public double DoOperation(double num1, double num2, string op)
{
double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.
writer.WriteStartObject();
writer.WritePropertyName("Operand1");
writer.WriteValue(num1);
writer.WritePropertyName("Operand2");
writer.WriteValue(num2);
writer.WritePropertyName("Operation");
// Use a switch statement to do the math.
switch (op)
{
case "a":
result = num1 + num2;
writer.WriteValue("Add");
break;
case "s":
result = num1 - num2;
writer.WriteValue("Subtract");
break;
case "m":
result = num1 * num2;
writer.WriteValue("Multiply");
break;
case "d":
// Ask the user to enter a non-zero divisor.
if (num2 != 0)
{
result = num1 / num2;
}
writer.WriteValue("Divide");
break;
// Return text for an incorrect option entry.
default:
break;
}
writer.WritePropertyName("Result");
writer.WriteValue(result);
writer.WriteEndObject();
return result;
}
public void Finish()
{
writer.WriteEndArray();
writer.WriteEndObject();
writer.Close();
}
}
}
Och här är koden för Program.cs:
// Program.cs
using System;
using CalculatorLibrary;
namespace CalculatorProgram
{
class Program
{
static void Main(string[] args)
{
bool endApp = false;
// Display title as the C# console calculator app.
Console.WriteLine("Console Calculator in C#\r");
Console.WriteLine("------------------------\n");
Calculator calculator = new Calculator();
while (!endApp)
{
// Declare variables and set to empty.
string numInput1 = "";
string numInput2 = "";
double result = 0;
// Ask the user to type the first number.
Console.Write("Type a number, and then press Enter: ");
numInput1 = Console.ReadLine();
double cleanNum1 = 0;
while (!double.TryParse(numInput1, out cleanNum1))
{
Console.Write("This is not valid input. Please enter an integer value: ");
numInput1 = Console.ReadLine();
}
// Ask the user to type the second number.
Console.Write("Type another number, and then press Enter: ");
numInput2 = Console.ReadLine();
double cleanNum2 = 0;
while (!double.TryParse(numInput2, out cleanNum2))
{
Console.Write("This is not valid input. Please enter an integer value: ");
numInput2 = Console.ReadLine();
}
// Ask the user to choose an operator.
Console.WriteLine("Choose an operator from the following list:");
Console.WriteLine("\ta - Add");
Console.WriteLine("\ts - Subtract");
Console.WriteLine("\tm - Multiply");
Console.WriteLine("\td - Divide");
Console.Write("Your option? ");
string op = Console.ReadLine();
try
{
result = calculator.DoOperation(cleanNum1, cleanNum2, op);
if (double.IsNaN(result))
{
Console.WriteLine("This operation will result in a mathematical error.\n");
}
else Console.WriteLine("Your result: {0:0.##}\n", result);
}
catch (Exception e)
{
Console.WriteLine("Oh no! An exception occurred trying to do the math.\n - Details: " + e.Message);
}
Console.WriteLine("------------------------\n");
// Wait for the user to respond before closing.
Console.Write("Press 'n' and Enter to close the app, or press any other key and Enter to continue: ");
if (Console.ReadLine() == "n") endApp = true;
Console.WriteLine("\n"); // Friendly linespacing.
}
calculator.Finish();
return;
}
}
}
Här är den fullständiga koden för CalculatorLibrary.cs-filen när du har slutfört alla steg:
// 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();
}
}
}
Och här är koden för 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;
}
}
}
Nästa steg
Grattis till att du har slutfört den här handledningen! Om du vill veta mer fortsätter du med följande innehåll: