教學課程:在 Visual Studio 中擴充 C# 控制台應用程式和偵錯 (第 2 部分)
在本教學課程系列的第 2 部分中,您會深入探討每日開發所需的 Visual Studio 組建和偵錯功能。 這些功能包括管理多個專案、偵錯和參考第三方套件。 您會執行在本教學課程的第1部分 中建立的 C# 主控台應用程式,並探索Visual Studio整合開發環境 (IDE) 的某些功能。 本教學課程是兩部分教學課程系列的第 2 部分。
在本教學課程中,您會完成下列工作:
- 新增第二個專案。
- 引用程式庫並新增套件。
- 對程式代碼進行偵錯。
- 檢查已完成的程序代碼。
先決條件
若要完成本文,您可以使用下列其中一個計算機應用程式:
- 本教學課程第 1 部分 計算機主控台應用程式,。
- vs-tutorial-samples 存放庫中的 C# 計算機應用程式。 若要開始使用,從存放庫開啟應用程式。
新增另一個專案
實務上的程式碼涉及專案在一個方案中共同運作。 您可以將類別庫專案新增至計算機應用程式,以提供一些計算機函式。
在 Visual Studio 中,您可以使用功能表命令 [檔案]>[新增>新增專案] 來新增專案。 您也可以在 [方案總管] 中以滑鼠右鍵按兩下方案, 從操作功能表新增專案。
在 [方案總管]中,以滑鼠右鍵按兩下方案節點,然後選擇 [新增>新增專案]。
在 [新增專案] 視窗中,於 [搜尋] 方塊中鍵入 類別庫。 選擇 C# 類別庫 項目樣本,然後選取 [下一步]。
在 [設定新專案 ] 畫面的 [] 中,輸入 [CalculatorLibrary] 的專案名稱,然後選取 [下一步]。
當系統詢問時,請選擇 .NET 3.1。 Visual Studio 會建立新的專案,並將其新增至方案。
將 Class1.cs 檔案重新命名為 CalculatorLibrary.cs。 若要重新命名檔案,您可以在 [方案總管] 中以滑鼠右鍵按下名稱,然後選擇 [重新命名]、選取名稱,然後按 F2,或選取名稱,然後再次選取輸入。
訊息可能會詢問您是否要將檔案中對
Class1
的參考重新命名。 您回答的方式並不重要,因為您將在未來的步驟中取代程序代碼。現在新增項目參考,讓第一個專案可以使用新類別庫公開的 API。 以滑鼠右鍵按兩下 [計算機] 專案中 [相依性] 節點,然後選擇 [[新增專案參考]。
[參考管理員] 對話框隨即出現。 在此對話框中,您可以新增專案所需的其他專案、程式集和 COM DLL 的參考。
在 [參考管理員] 對話框中,選取 CalculatorLibrary 項目的複選框,然後選取 [確定]。
項目參考會出現在 [方案總管] 的 [專案] 節點下。
在 Program.cs中,選取
Calculator
類別及其所有程式代碼,然後按 Ctrl+X 來剪下它。 然後,在 CalculatorLibrary.cs中,將程式代碼貼到CalculatorLibrary
命名空間中。此外,請在 Calculator 類別之前新增
public
,以在連結庫外公開它。CalculatorLibrary.cs 現在應該類似下列程式代碼:
// 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 也有參考,但錯誤指出
Calculator.DoOperation
呼叫無法解決。 錯誤是因為CalculatorLibrary
位於不同的命名空間中。 如需完整參考,您可以在CalculatorLibrary
中將Calculator.DoOperation
命名空間新增至 呼叫:// Program.cs result = CalculatorLibrary.Calculator.DoOperation(cleanNum1, cleanNum2, op);
或者,您可以嘗試將
using
指示詞新增至 Program.cs 檔案的開頭:// Program.cs using CalculatorLibrary;
新增
using
指令應該讓您從呼叫位置移除CalculatorLibrary
命名空間,但現在出現了歧義。Calculator
是CalculatorLibrary
中的類別,還是Calculator
是命名空間?若要解決模棱兩可的情況,請將命名空間從
Calculator
重新命名為CalculatorProgram
中的 。// Program.cs namespace CalculatorProgram
在 [方案總管]中,以滑鼠右鍵按兩下方案節點,然後選擇 [新增>新增專案]。
在 [新增專案] 視窗中,於 [搜尋] 方塊中鍵入 類別庫。 選擇 C# 類別庫 項目樣本,然後選取 [下一步]。
在 [設定新專案 ] 畫面的 [] 中,輸入 [CalculatorLibrary] 的專案名稱,然後選取 [下一步]。
在 [其他資訊 的畫面上,已選擇 .NET 8.0。 選取 [建立 ]。
Visual Studio 會建立新的專案,並將其新增至方案。
將 Class1.cs 檔案重新命名為 CalculatorLibrary.cs。 若要重新命名檔案,您可以在 [方案總管] 中以滑鼠右鍵按下名稱,然後選擇 [重新命名]、選取名稱,然後按 F2,或選取名稱,然後再次選取輸入。
訊息可能會詢問您是否要重新命名檔案中
Class1
的所有引用。 您回答的方式並不重要,因為您將在未來的步驟中取代程序代碼。現在新增項目參考,讓第一個專案可以使用新類別庫公開的 API。 以滑鼠右鍵按兩下 [計算機] 專案中 [相依性] 節點,然後選擇 [[新增專案參考]。
[參考管理員] 對話框隨即出現。 在此對話框中,您可以新增專案所需的其他專案、程式集和 COM DLL 的參考。
在 [參考管理員] 對話框中,選取 CalculatorLibrary 項目的複選框,然後選取 [確定]。
項目參考會出現在 [方案總管] 的 [專案] 節點下。
在 Program.cs中,選取
Calculator
類別及其所有程式代碼,然後按 Ctrl+X 來剪下它。 然後,在 CalculatorLibrary.cs中,將程式代碼貼到CalculatorLibrary
命名空間中。此外,請在 Calculator 類別之前新增
public
,以在連結庫外公開它。CalculatorLibrary.cs 現在應該類似下列程式代碼:
// 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 也有參考,但錯誤指出
Calculator.DoOperation
呼叫無法解決。 錯誤是因為CalculatorLibrary
位於不同的命名空間中。 如需完整參考,您可以在CalculatorLibrary
中將Calculator.DoOperation
命名空間新增至 呼叫:// Program.cs result = CalculatorLibrary.Calculator.DoOperation(cleanNum1, cleanNum2, op);
或者,您可以嘗試將
using
指示詞新增至 Program.cs 檔案的開頭:// Program.cs using CalculatorLibrary;
新增
using
指令可以讓您從呼叫點移除CalculatorLibrary
命名空間。如果您的
Program.cs
程式代碼位於Calculator
命名空間中,請將命名空間從Calculator
重新命名為CalculatorProgram
,以移除類別名稱和命名空間名稱之間的模棱兩可。
參考 .NET 程式庫:寫入日誌
您可以使用 .NET Trace 類別來新增所有作業的記錄,並將其寫入文本檔。
Trace
類別也適用於基本列印偵錯技術。
Trace
類別位於 System.Diagnostics
中,並使用 System.IO
等 StreamWriter
類別。
從將
using
指令新增到 CalculatorLibrary.cs的頂端開始:// CalculatorLibrary.cs using System.IO; using System.Diagnostics;
在使用這個
Trace
類別時,必須保存對該類別的參考,並且該類別與文件流相關聯。 該需求表示計算機在 對象中運作得更好,因此請在Calculator
中的 類別開頭新增建構函式。此外,請移除
static
關鍵詞,將靜態DoOperation
方法變更為成員方法。// 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) {
將記錄輸出新增至每個計算。
DoOperation
現在看起來應該像下列程序代碼:// 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; }
回到 Program.cs,紅色波浪線現在會標幟靜態呼叫。 若要修正錯誤,請在
calculator
迴圈之前新增下列程式代碼行,以建立while (!endApp)
變數:// Program.cs Calculator calculator = new Calculator();
同時修改
DoOperation
呼叫位置,以小寫形式參照名為calculator
的物件。 程式代碼現在是成員調用,而不是對靜態方法的呼叫。// Program.cs result = calculator.DoOperation(cleanNum1, cleanNum2, op);
再次執行應用程式。 完成後,使用滑鼠右鍵點擊 [計算機] [] 專案節點,然後選擇 [在檔案總管中開啟資料夾] []。
在 [檔案總管] 中,流覽至 [bin/Debug/net8.0 底下的輸出資料夾(或您使用的任何 .NET 版本),然後開啟 calculator.log 檔案。 輸出看起來應該像這樣:
Starting Calculator Log Started 7/9/2020 1:58:19 PM 1 + 2 = 3 3 * 3 = 9
此時,CalculatorLibrary.cs 應該類似下列程序代碼:
// 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 看起來應該像下列程式代碼:
// 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;
}
}
}
您可以使用 .NET Trace 類別來新增所有作業的記錄,並將其寫入文本檔。
Trace
類別也適用於基本列印偵錯技術。
Trace
類別位於 System.Diagnostics
中,並使用 System.IO
等 StreamWriter
類別。
從將
using
指令新增到 CalculatorLibrary.cs的頂端開始:// CalculatorLibrary.cs using System.Diagnostics;
在使用這個
Trace
類別時,必須保存對該類別的參考,並且該類別與文件流相關聯。 該需求表示計算機在 對象中運作得更好,因此請在Calculator
中的 類別開頭新增建構函式。此外,請移除
static
關鍵詞,將靜態DoOperation
方法變更為成員方法。// 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) {
將記錄輸出新增至每個計算。
DoOperation
現在看起來應該像下列程序代碼:// 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; }
回到 Program.cs,紅色波浪線現在會標幟靜態呼叫。 若要修正錯誤,請在
calculator
迴圈之前新增下列程式代碼行,以建立while (!endApp)
變數:// Program.cs Calculator calculator = new Calculator();
同時修改
DoOperation
呼叫位置,以小寫形式參照名為calculator
的物件。 程式代碼現在是成員調用,而不是對靜態方法的呼叫。// Program.cs result = calculator.DoOperation(cleanNum1, cleanNum2, op);
再次執行應用程式。 完成後,使用滑鼠右鍵點擊 [計算機] [] 專案節點,然後選擇 [在檔案總管中開啟資料夾] []。
在 [檔案總管] 中,流覽至 [bin/Debug/下的輸出資料夾,然後開啟 calculator.log 檔案。 輸出看起來應該像這樣:
Starting Calculator Log Started 7/9/2020 1:58:19 PM 1 + 2 = 3 3 * 3 = 9
此時,CalculatorLibrary.cs 應該類似下列程序代碼:
// 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 看起來應該像下列程式代碼:
// 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;
}
}
}
新增 NuGet 套件:寫入 JSON 檔案
若要以 JSON 輸出作業,這是儲存對象資料的熱門且可攜式格式,您可以參考 nuGet 套件 Newtonsoft.Json。 NuGet 套件是 .NET 類別庫的主要散發方法。
在 [方案總管]中,以滑鼠右鍵按兩下 CalculatorLibrary 專案的 [相依性] 節點,然後選擇 [管理 NuGet 套件]。
NuGet 套件管理員隨即開啟。
搜尋並選取 Newtonsoft.Json 套件,然後選取「安裝」。
Visual Studio 會下載套件,並將其新增至專案。 在 [方案總管]的 [參考] 節點中,會出現一個新的項目。
如果系統提示您是否接受變更,請選擇 [確定] 。
Visual Studio 會下載套件,並將其新增至專案。 [方案總管]中的 套件 節點會出現一個新的項目。
在
using
開頭,新增Newtonsoft.Json
指令以供 使用。// CalculatorLibrary.cs using Newtonsoft.Json;
建立
JsonWriter
成員物件,並以下列程式代碼取代Calculator
建構函式:// 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(); }
修改
DoOperation
方法以新增 JSONwriter
程式代碼:// 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; }
新增方法以在使用者完成輸入作業數據之後完成 JSON 語法。
// CalculatorLibrary.cs public void Finish() { writer.WriteEndArray(); writer.WriteEndObject(); writer.Close(); }
在 Program.cs結尾,於
return;
之前,添加一個呼叫至Finish
:// Program.cs // Add call to close the JSON writer before return calculator.Finish(); return; }
建置並執行應用程式,並在您完成輸入幾個作業之後,輸入 n 命令來關閉應用程式。
在檔案總管中開啟 calculatorlog.json 檔案。 您應該會看到類似下列內容的內容:
{ "Operations": [ { "Operand1": 2.0, "Operand2": 3.0, "Operation": "Add", "Result": 5.0 }, { "Operand1": 3.0, "Operand2": 4.0, "Operation": "Multiply", "Result": 12.0 } ] }
偵錯:設定並達到斷點
Visual Studio 調試程式是功能強大的工具。 調試程式可以逐步執行您的程式代碼,找出程式設計錯誤所在的確切點。 接著,您可以瞭解您需要進行哪些修正,並進行暫時變更,以便繼續執行您的應用程式。
在 Program.cs中,點擊以下代碼行左邊的裝訂線。 您也可以點選該行,然後選取 F9,或以滑鼠右鍵點選該行,然後選取 [斷點],>[插入斷點]。
// Program.cs result = calculator.DoOperation(cleanNum1, cleanNum2, op);
出現的紅點表示斷點。 您可以使用斷點來暫停應用程式並檢查程式代碼。 您可以在任何可執行的程式代碼行上設定斷點。
建置並執行應用程式。 輸入下列值以進行計算:
- 在第一個數位中,輸入 8。
- 針對第二個數字,輸入 0。
- 對於操作員,讓我們來點樂子。 輸入 d。
應用程式會在您建立斷點的地方暫停,此斷點由左邊的黃色指標和醒目的代碼表示。 醒目提示的程式代碼尚未執行。
現在,隨著應用程式暫停,您可以檢查應用程式狀態。
偵錯:檢視變數
在醒目提示的程式代碼中,將滑鼠停留在變數上,例如
cleanNum1
和op
。 這些變數的目前值分別8
和d
會出現在DataTips中。偵錯時,檢查變數是否保存您預期的值,對於修正問題通常很重要。
在下方窗格中,查看 區域 視窗。 如果它被關閉,請選取 [偵錯]>Windows>[局部變數] 以開啟。
[局部變數] 視窗會顯示當前作用域中的每個變數,以及它們的值和類型。
查看 [自動] 視窗。
[自動變數] 視窗與 [局部變數] 視窗相似,但會顯示在應用程式暫停時,程式代碼行前後的變數。
注意
如果您沒有看到 [自動變數] 視窗,請選取 [偵錯]>Windows>[自動] 來開啟它。
接下來,在調試器中逐步執行程式碼語句,這被稱為單步執行。
偵錯:逐步執行程式碼
按 F11,或選取 [偵錯]>[逐步執行]。
使用 [逐步執行] 命令時,應用程式會執行目前的語句,並前進到下一個可執行語句,通常是下一行程序代碼。 左邊的黃色指標一律會指出目前的語句。
您剛進入
DoOperation
方法中的Calculator
類別。若要以階層方式檢視程式流程,請查看 [呼叫堆疊] 視窗。 如果已關閉,請選取 偵錯>Windows>呼叫堆疊 將其開啟。
的螢幕快照
此檢視會顯示目前
Calculator.DoOperation
方法,以黃色指標表示。 第二列顯示Main
中的 方法,這個方法是由該函式呼叫的。呼叫堆疊 視窗會顯示呼叫方法和函式的順序。 此視窗也可從其快捷方式功能表存取許多調試程式功能,例如 移至原始程式碼。
按 F10,或重複選取 [偵錯]>[逐步執行],直到應用程式暫停在
switch
語句上。// CalculatorLibrary.cs switch (op) {
Step Over 命令類似於 [逐步執行] 命令,不同之處在於,如果目前的語句呼叫函式,調試器會運行該函式中的代碼,並且在函式返回之前不會暫停執行。 如果您對特定函式不感興趣,則「略過」比「進入」更快。
再按 F10 一次,讓應用程式在下列程式代碼行暫停。
// CalculatorLibrary.cs if (num2 != 0) {
此程式代碼會檢查零除大小寫。 如果應用程式繼續運行,它會拋出一般例外狀況(錯誤),但你可能想嘗試其他方法,例如在控制台查看實際返回的值。 其中一個選項是使用稱為 編輯後繼續 的調試程式功能來變更程式代碼,然後繼續偵錯。 不過,暫時修改執行流程有另一種技巧。
偵錯:測試暫時性變更
選取目前在
if (num2 != 0)
語句上暫停的黃色指標,並將其拖曳至下列語句:// CalculatorLibrary.cs result = num1 / num2;
拖曳這裡的指標會導致應用程式完全略過
if
語句,因此您可以看到當您除以零時會發生什麼事。按 F10 以執行程式碼行。
如果您將滑鼠停留在
result
變數上,它會顯示 Infinity的值。 在 C# 中,Infinity 是除以零時的結果。按 F5 ,或選取 [偵錯]>[繼續偵錯]。
無限符號會出現在控制台中,作為數學運算的結果。
輸入 n 命令,以正確關閉應用程式。
程式代碼完成
以下是完成所有步驟之後,CalculatorLibrary.cs 檔案的完整程序代碼:
// 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();
}
}
}
以下是 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;
}
}
}
以下是完成所有步驟之後,CalculatorLibrary.cs 檔案的完整程序代碼:
// 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();
}
}
}
以下是 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;
}
}
}
後續步驟
恭喜您完成本教學課程! 若要深入瞭解,請繼續進行下列內容: