教學課程:在 Visual Studio 中擴充 C# 主控台應用程式和偵錯 (第 2 部分之 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 現在應該類似下列程式碼:
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
呼叫:result = CalculatorLibrary.Calculator.DoOperation(cleanNum1, cleanNum2, op);
或者,您可以嘗試將
using
指示詞新增至檔案的開頭:using CalculatorLibrary;
新增
using
指示詞應該可讓您從呼叫網站移除CalculatorLibrary
命名空間,但現在語意模糊的情況。CalculatorLibrary
中的類別是Calculator
,還是Calculator
命名空間?若要解決語意模糊的情況,請將 Program.cs 中的命名空間從
Calculator
重新命名為CalculatorProgram
。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 現在應該類似下列程式碼:
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
呼叫:result = CalculatorLibrary.Calculator.DoOperation(cleanNum1, cleanNum2, op);
或者,您可以嘗試將
using
指示詞新增至檔案的開頭:using CalculatorLibrary;
新增
using
指示詞應該可讓您從呼叫網站移除CalculatorLibrary
命名空間,但現在語意模糊的情況。CalculatorLibrary
中的類別是Calculator
,還是Calculator
命名空間?若要解決語意模糊的情況,請將 Program.cs 中的命名空間從
Calculator
重新命名為CalculatorProgram
。namespace CalculatorProgram
參考 .NET 程式庫:寫入記錄檔
您可以使用 .NET Trace 類別來新增所有作業的記錄,並將其寫入文字檔。 類別 Trace
也適用於基本列印偵錯技術。 類別 Trace
位於 System.Diagnostics
中,並使用類似 StreamWriter
的 System.IO
類別。
從在 CalculatorLibrary.cs 頂端新增
using
指示詞開始:using System.IO; using System.Diagnostics;
Trace
類別的這個使用方式必須保存類別的參考,而該類別會與 filestream 產生關聯。 該需求表示計算機在物件中運作得更好,因此請在 CalculatorLibrary.cs 中的Calculator
類別開頭新增建構函式。此外,請移除
static
關鍵字,將靜態DoOperation
方法變更為成員方法。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
現在應該看起來像下列程式碼: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,紅色波浪底線現在會標幟靜態呼叫。 若要修正錯誤,請在
while (!endApp)
迴圈之前新增下列程式碼來建立calculator
變數:Calculator calculator = new Calculator();
同時修改
DoOperation
呼叫網站,以參考以小寫命名calculator
的物件。 程式碼現在是成員引動,而不是對靜態方法的呼叫。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 應該類似下列程式碼:
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 看起來應該像下列程式碼:
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
中,並使用類似 StreamWriter
的 System.IO
類別。
從在 CalculatorLibrary.cs 頂端新增
using
指示詞開始:using System.Diagnostics;
Trace
類別的這個使用方式必須保存類別的參考,而該類別會與 filestream 產生關聯。 該需求表示計算機在物件中運作得更好,因此請在 CalculatorLibrary.cs 中的Calculator
類別開頭新增建構函式。此外,請移除
static
關鍵字,將靜態DoOperation
方法變更為成員方法。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
現在應該看起來像下列程式碼: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,紅色波浪底線現在會標幟靜態呼叫。 若要修正錯誤,請在
while (!endApp)
迴圈之前新增下列程式碼來建立calculator
變數:Calculator calculator = new Calculator();
同時修改
DoOperation
呼叫網站,以參考以小寫命名calculator
的物件。 程式碼現在是成員引動,而不是對靜態方法的呼叫。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 應該類似下列程式碼:
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 看起來應該像下列程式碼:
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;
}
}
}
新增 NuGet 套件:寫入 JSON 檔案
若要以 JSON 輸出作業,這是用來儲存物件資料的熱門可攜式格式,您可以參考 Newtonsoft.Json NuGet 套件。 NuGet 套件是 .NET 類別庫的主要散發方法。
在 [方案總管] 中,以滑鼠右鍵按一下 CalculatorLibrary 專案的 [相依性] 節點,然後選擇 [管理 NuGet 套件]。
NuGet 套件管理員隨即開啟。
搜尋並選取 Newtonsoft.Json 套件,然後選取 [安裝]。
Visual Studio 會下載套件,並將其新增至專案。 [方案總管] 中的 [參考] 節點中會出現新的項目。
如果系統提示您是否接受變更,請選取 [確定]。
Visual Studio 會下載套件,並將其新增至專案。 新的專案會出現在 [方案總管] 的 [套件] 節點中。
在 CalculatorLibrary.cs 的開頭新增
using
指示詞Newtonsoft.Json
。using Newtonsoft.Json;
建立
JsonWriter
成員物件,並以下列程式碼取代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(); }
修改
DoOperation
方法以新增 JSONwriter
程式碼: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 語法。
public void Finish() { writer.WriteEndArray(); writer.WriteEndObject(); writer.Close(); }
在 Program.cs 結尾處,於
return;
之前,新增對Finish
的呼叫:// 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,或以滑鼠右鍵按一下該行,然後選取 [中斷點]>[插入中斷點]。
result = calculator.DoOperation(cleanNum1, cleanNum2, op);
出現的紅點表示中斷點。 您可以使用中斷點來暫停應用程式並檢查程式碼。 您可以在任何可執行的程式碼上設定中斷點。
建置並執行應用程式。 輸入下列值以進行計算:
- 針對第一個數字,輸入 8。
- 針對第二個數字,輸入 0。
- 針對運算子,讓我們有一些樂趣。 輸入 d。
應用程式會暫停您建立中斷點的位置,此中斷點是由左邊的黃色指標和醒目提示的程式碼表示。 醒目提示的程式碼尚未執行。
現在,隨著應用程式暫停,您可以檢查應用程式狀態。
偵錯:檢視變數
在醒目提示的程式碼中,將滑鼠暫留在
cleanNum1
和op
等變數上。 這些變數 (8
和d
) 的目前值分別會出現在 DataTips 中。偵錯時,檢查變數是否保存您預期的值,對於修正問題通常很重要。
在下方窗格中,查看 [區域變數] 視窗。 如果關閉,請選取 [偵錯]>[視窗]>[區域變數] 以開啟它。
[區域變數] 視窗會顯示目前在範圍中的每個變數,以及其值和型別。
讓我們看看 [自動變數] 視窗。
[自動變數] 視窗類似於 [區域變數] 視窗,但會顯示緊接在應用程式暫停所在目前程式碼之前和之後的變數。
注意
如果您沒有看到 [自動變數] 視窗,請選取 [偵錯]>[視窗]>[自動變數] 以開啟它。
接下來,一次在偵錯工具中執行一個陳述式中的程式碼,稱為 逐步執行。
偵錯:逐步執行程式碼
按 F11,或選取 [偵錯]>[逐步執行]。
使用 [逐步執行] 命令時,應用程式會執行目前的陳述式,並前進到下一個可執行的陳述式,通常是下一行程式碼。 左邊的黃色指標始終會指出目前的陳述式。
您剛逐步執行
Calculator
類別中的DoOperation
方法。若要取得程式流程的階層式查看,請查看 [呼叫堆疊] 視窗。 如果關閉,請選取 [偵錯]>[視窗]>[呼叫堆疊] 以開啟它。
這個檢視會顯示目前的
Calculator.DoOperation
方法,以黃色指標表示。 第二個資料列會顯示從 Program.cs 中的Main
方法呼叫 方法的函式。[呼叫堆疊] 視窗會顯示方法和函式的呼叫順序。 此視窗也可從其捷徑功能表存取許多個偵錯工具功能,例如 [移至原始程式碼]。
按 F10,或選取 [偵錯]>[逐步執行] 數次,直到應用程式暫停
switch
陳述式為止。switch (op) {
Step Over 命令類似於 [逐步執行] 命令,不同之處在於,如果目前的陳述式呼叫函式,偵錯工具會在函式中執行程式碼,而且在函式傳回之前不會暫停執行。 如果您對特定函式不感興趣,則「Step Over」比「逐步執行」更快。
再按 F10 鍵,讓應用程式在下列程式碼暫停。
if (num2 != 0) {
此程式碼會檢查除以零案例。 如果應用程式繼續,它會擲回一般例外狀況(錯誤),但您可能會想要嘗試其他專案,例如在控制台中檢視實際傳回的值。 其中一個選項是使用名為 edit-and-continue 的偵錯工具功能來變更程式碼,然後繼續偵錯。 不過,暫時修改執行流程有另一種技巧。
偵錯:測試暫時性變更
選取目前暫停於
if (num2 != 0)
陳述式上的黃色指標,並將它拖曳至下列陳述式:result = num1 / num2;
拖曳這裡的指標會導致應用程式完全略過
if
陳述式,因此您可以看到當您除以零時會發生什麼事。按 F10 以執行程式碼。
如果您將滑鼠暫留在
result
變數上,它會顯示 Infinity 的值。 在 C# 中,Infinity 是除以零時的結果。按 F5,或選取 [偵錯]>[繼續偵錯]。
Infinity 符號會出現在主控台中,作為數學運算的結果。
輸入 n 命令,以正確關閉應用程式。
程式碼完成
以下是 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 的程式碼:
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 檔案的完整程式碼,在您完成所有步驟之後:
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 的程式碼:
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;
}
}
}
下一步
恭喜您完成此教學課程! 若要深入了解,請繼續進行下列內容: