教學課程:在 Visual Studio 中擴充 C# 主控台應用程式和偵錯 (第 2 部分之 2)

在本教學課程系列的第 2 部分中,您會深入探討每日開發所需的 Visual Studio 組建和偵錯功能。 這些功能包括管理多個專案、偵錯和參考協力廠商套件。 您會執行本教學課程第 1 部分所建立的 C# 主控台應用程式,並探索 Visual Studio 整合式開發環境 (IDE) 的某些功能。 本教學課程是兩部分教學課程系列的第 2 部分。

在本教學課程中,您會完成下列工作:

  • 新增第二個專案。
  • 參考程式庫並新增套件。
  • 為程式碼偵錯。
  • 檢查已完成的程式碼。

必要條件

若要完成本文,您可以使用下列其中一個計算機應用程式:

新增另一個專案

真實世界程式碼牽涉到專案在方案中共同作業。 您可以將類別庫專案新增至計算機應用程式,以提供一些計算機函式。

在 Visual Studio 中,您可以使用功能表命令 [檔案]>[新增]>[新增專案] 來新增專案。 您也可以以滑鼠右鍵按一下 [方案總管] 中的方案,以從捷徑功能表新增專案。

  1. [方案總管] 中,以滑鼠右鍵按一下解決方案節點,然後選擇 [新增]>[新增專案]

  2. [新增專案] 視窗中,於 [搜尋] 方塊中輸入 類別庫。 選擇 C# 類別庫 專案範本,然後選取 [下一步]

    Screenshot of Class Library project template selection.

  3. [設定新專案] 畫面上,輸入專案名稱 CalculatorLibrary,然後選取 [下一步]

  4. 當系統詢問時,請選擇 .NET 3.1。 Visual Studio 會建立新的專案,並將其新增至方案。

    Screenshot of Solution Explorer with the CalculatorLibrary class library project added.

  5. Class1.cs 檔案重新命名為 CalculatorLibrary.cs。 若要重新命名檔案,您可以在 方案總管以滑鼠右鍵按下名稱,然後選擇 [重新命名]、選取名稱並按 F2,或選取名稱,然後再次選取以輸入。

    訊息可能會詢問您是否要將檔案中的參考重新命名為 Class1。 您回答的方式並不重要,因為您將在未來的步驟中取代程式碼。

  6. 現在新增專案參考,讓第一個專案可以使用新類別庫公開的 API。 以滑鼠右鍵按一下計算機專案中的 [相依性] 節點,然後選擇 [新增專案參考]

    Screenshot of the Add Project Reference menu item.

    [參考管理員] 對話方塊隨即顯示。 在此對話方塊中,您可以新增專案所需的其他專案、組件和 COM DLL 參考。

  7. [參考管理員] 對話方塊中,選取 [CalculatorLibrary] 專案的核取方塊,然後選取 [確定]

    Screenshot of the Reference Manager dialog box.

    專案參考會出現在 [方案總管] 中的 [專案] 節點底下。

    Screenshot of Solution Explorer with project reference.

  8. 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;
             }
         }
     }
    
  9. 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
    
  1. [方案總管] 中,以滑鼠右鍵按一下解決方案節點,然後選擇 [新增]>[新增專案]

  2. [新增專案] 視窗中,於 [搜尋] 方塊中輸入 類別庫。 選擇 C# 類別庫 專案範本,然後選取 [下一步]

    Screenshot of Class Library project template selection.

  3. [設定新專案] 畫面上,輸入專案名稱 CalculatorLibrary,然後選取 [下一步]

  4. 在 [ 其他資訊] 畫面上, 已選取 .NET 8.0 。 選取 建立

    Visual Studio 會建立新的專案,並將其新增至方案。

    Screenshot of Solution Explorer with the CalculatorLibrary class library project added.

  5. Class1.cs 檔案重新命名為 CalculatorLibrary.cs。 若要重新命名檔案,您可以在 方案總管以滑鼠右鍵按下名稱,然後選擇 [重新命名]、選取名稱並按 F2,或選取名稱,然後再次選取以輸入。

    訊息可能會詢問您是否要將檔案中的所有參考重新命名為 Class1。 您回答的方式並不重要,因為您將在未來的步驟中取代程式碼。

  6. 現在新增專案參考,讓第一個專案可以使用新類別庫公開的 API。 以滑鼠右鍵按一下計算機專案中的 [相依性] 節點,然後選擇 [新增專案參考]

    Screenshot of the Add Project Reference menu item.

    [參考管理員] 對話方塊隨即顯示。 在此對話方塊中,您可以新增專案所需的其他專案、組件和 COM DLL 參考。

  7. [參考管理員] 對話方塊中,選取 [CalculatorLibrary] 專案的核取方塊,然後選取 [確定]

    Screenshot of the Reference Manager dialog box.

    專案參考會出現在 [方案總管] 中的 [專案] 節點底下。

    Screenshot of Solution Explorer with project reference.

  8. 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;
             }
         }
     }
    
  9. 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 中,並使用類似 StreamWriterSystem.IO 類別。

  1. 從在 CalculatorLibrary.cs 頂端新增 using 指示詞開始:

    using System.IO;
    using System.Diagnostics;
    
  2. 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)
       {
    
  3. 將記錄輸出新增至每個計算方式。 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;
     }
    
  4. 回到 Program.cs,紅色波浪底線現在會標幟靜態呼叫。 若要修正錯誤,請在 while (!endApp) 迴圈之前新增下列程式碼來建立 calculator 變數:

    Calculator calculator = new Calculator();
    

    同時修改 DoOperation 呼叫網站,以參考以小寫命名 calculator 的物件。 程式碼現在是成員引動,而不是對靜態方法的呼叫。

    result = calculator.DoOperation(cleanNum1, cleanNum2, op);
    
  5. 重新執行應用程式。 完成時,以滑鼠右鍵按一下 [計算機] 專案節點,然後選擇 [檔案總管] 中的 [開啟資料夾]

  6. 在 [檔案總管] 中,瀏覽至 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 中,並使用類似 StreamWriterSystem.IO 類別。

  1. 從在 CalculatorLibrary.cs 頂端新增 using 指示詞開始:

    using System.Diagnostics;
    
  2. 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)
       {
    
  3. 將記錄輸出新增至每個計算方式。 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;
     }
    
  4. 回到 Program.cs,紅色波浪底線現在會標幟靜態呼叫。 若要修正錯誤,請在 while (!endApp) 迴圈之前新增下列程式碼來建立 calculator 變數:

    Calculator calculator = new Calculator();
    

    同時修改 DoOperation 呼叫網站,以參考以小寫命名 calculator 的物件。 程式碼現在是成員引動,而不是對靜態方法的呼叫。

    result = calculator.DoOperation(cleanNum1, cleanNum2, op);
    
  5. 重新執行應用程式。 完成時,以滑鼠右鍵按一下 [計算機] 專案節點,然後選擇 [檔案總管] 中的 [開啟資料夾]

  6. 在 [檔案總管] 中,瀏覽至 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 類別庫的主要散發方法。

  1. [方案總管] 中,以滑鼠右鍵按一下 CalculatorLibrary 專案的 [相依性] 節點,然後選擇 [管理 NuGet 套件]

    Screenshot of Manage NuGet Packages on the shortcut menu.

    Screenshot of Manage NuGet Packages on the shortcut menu.

    NuGet 套件管理員隨即開啟。

    Screenshot of the NuGet Package Manager.

  2. 搜尋並選取 Newtonsoft.Json 套件,然後選取 [安裝]

    Screenshot of Newtonsoft J SON NuGet package information in the NuGet Package Manager.

    Visual Studio 會下載套件,並將其新增至專案。 [方案總管] 中的 [參考] 節點中會出現新的項目。

    Screenshot of Newtonsoft J SON NuGet package information in the NuGet Package Manager. 如果系統提示您是否接受變更,請選取 [確定]

    Visual Studio 會下載套件,並將其新增至專案。 新的專案會出現在 [方案總管][套件] 節點中。

    CalculatorLibrary.cs 的開頭新增 using 指示詞Newtonsoft.Json

    using Newtonsoft.Json;
    
  3. 建立 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();
         }
    
  4. 修改 DoOperation 方法以新增 JSON writer 程式碼:

         public double DoOperation(double num1, double num2, string op)
         {
             double result = double.NaN; // Default value is "not-a-number" if an operation, such as division, could result in an error.
             writer.WriteStartObject();
             writer.WritePropertyName("Operand1");
             writer.WriteValue(num1);
             writer.WritePropertyName("Operand2");
             writer.WriteValue(num2);
             writer.WritePropertyName("Operation");
             // Use a switch statement to do the math.
             switch (op)
             {
                 case "a":
                     result = num1 + num2;
                     writer.WriteValue("Add");
                     break;
                 case "s":
                     result = num1 - num2;
                     writer.WriteValue("Subtract");
                     break;
                 case "m":
                     result = num1 * num2;
                     writer.WriteValue("Multiply");
                     break;
                 case "d":
                     // Ask the user to enter a non-zero divisor.
                     if (num2 != 0)
                     {
                         result = num1 / num2;
                     }
                     writer.WriteValue("Divide");
                     break;
                 // Return text for an incorrect option entry.
                 default:
                     break;
             }
             writer.WritePropertyName("Result");
             writer.WriteValue(result);
             writer.WriteEndObject();
    
             return result;
         }
    
  5. 新增方法以在使用者完成輸入作業資料之後完成 JSON 語法。

     public void Finish()
     {
         writer.WriteEndArray();
         writer.WriteEndObject();
         writer.Close();
     }
    
  6. Program.cs 結尾處,於 return; 之前,新增對 Finish 的呼叫:

             // Add call to close the JSON writer before return
             calculator.Finish();
             return;
         }
    
  7. 組建並執行應用程式,並在您完成輸入幾個作業之後,輸入 n 命令來關閉應用程式。

  8. 在 [檔案總管] 中開啟 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 偵錯工具是一個功能強大的工具。 偵錯工具可以逐步執行您的程式碼,找出程式設計錯誤所在的確切點。 接著,您可以了解需要進行哪些修正,並進行暫時變更,以便繼續執行您的應用程式。

  1. Program.cs 中,按一下下列程式碼左邊的裝訂邊。 您也可以按一下該行並選取 F9,或以滑鼠右鍵按一下該行,然後選取 [中斷點]>[插入中斷點]

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

    出現的紅點表示中斷點。 您可以使用中斷點來暫停應用程式並檢查程式碼。 您可以在任何可執行的程式碼上設定中斷點。

    Screenshot that shows setting a breakpoint.

  2. 建置並執行應用程式。 輸入下列值以進行計算:

    • 針對第一個數字,輸入 8
    • 針對第二個數字,輸入 0
    • 針對運算子,讓我們有一些樂趣。 輸入 d

    應用程式會暫停您建立中斷點的位置,此中斷點是由左邊的黃色指標和醒目提示的程式碼表示。 醒目提示的程式碼尚未執行。

    Screenshot of hitting a breakpoint

    現在,隨著應用程式暫停,您可以檢查應用程式狀態。

偵錯:檢視變數

  1. 在醒目提示的程式碼中,將滑鼠暫留在 cleanNum1op 等變數上。 這些變數 (8d) 的目前值分別會出現在 DataTips 中。

    Screenshot that shows viewing a DataTip.

    偵錯時,檢查變數是否保存您預期的值,對於修正問題通常很重要。

  2. 在下方窗格中,查看 [區域變數] 視窗。 如果關閉,請選取 [偵錯]>[視窗]>[區域變數] 以開啟它。

    [區域變數] 視窗會顯示目前在範圍中的每個變數,以及其值和型別。

    Screenshot of the Locals window.

    Screenshot of the Locals window.

  3. 讓我們看看 [自動變數] 視窗。

    [自動變數] 視窗類似於 [區域變數] 視窗,但會顯示緊接在應用程式暫停所在目前程式碼之前和之後的變數。

    注意

    如果您沒有看到 [自動變數] 視窗,請選取 [偵錯]>[視窗]>[自動變數] 以開啟它。

接下來,一次在偵錯工具中執行一個陳述式中的程式碼,稱為 逐步執行

偵錯:逐步執行程式碼

  1. F11,或選取 [偵錯]>[逐步執行]

    使用 [逐步執行] 命令時,應用程式會執行目前的陳述式,並前進到下一個可執行的陳述式,通常是下一行程式碼。 左邊的黃色指標始終會指出目前的陳述式。

    Screenshot of step into command

    您剛逐步執行 Calculator 類別中的 DoOperation 方法。

  2. 若要取得程式流程的階層式查看,請查看 [呼叫堆疊] 視窗。 如果關閉,請選取 [偵錯]>[視窗]>[呼叫堆疊] 以開啟它。

    Screenshot of the call stack

    這個檢視會顯示目前的 Calculator.DoOperation 方法,以黃色指標表示。 第二個資料列會顯示從 Program.cs 中的 Main 方法呼叫 方法的函式。

    [呼叫堆疊] 視窗會顯示方法和函式的呼叫順序。 此視窗也可從其捷徑功能表存取許多個偵錯工具功能,例如 [移至原始程式碼]

  3. F10,或選取 [偵錯]>[逐步執行] 數次,直到應用程式暫停 switch 陳述式為止。

    switch (op)
    {
    

    Step Over 命令類似於 [逐步執行] 命令,不同之處在於,如果目前的陳述式呼叫函式,偵錯工具會在函式中執行程式碼,而且在函式傳回之前不會暫停執行。 如果您對特定函式不感興趣,則「Step Over」比「逐步執行」更快。

  4. 再按 F10 鍵,讓應用程式在下列程式碼暫停。

    if (num2 != 0)
    {
    

    此程式碼會檢查除以零案例。 如果應用程式繼續,它會擲回一般例外狀況(錯誤),但您可能會想要嘗試其他專案,例如在控制台中檢視實際傳回的值。 其中一個選項是使用名為 edit-and-continue 的偵錯工具功能來變更程式碼,然後繼續偵錯。 不過,暫時修改執行流程有另一種技巧。

偵錯:測試暫時性變更

  1. 選取目前暫停於 if (num2 != 0) 陳述式上的黃色指標,並將它拖曳至下列陳述式:

    result = num1 / num2;
    

    拖曳這裡的指標會導致應用程式完全略過 if 陳述式,因此您可以看到當您除以零時會發生什麼事。

  2. F10 以執行程式碼。

  3. 如果您將滑鼠暫留在 result 變數上,它會顯示 Infinity 的值。 在 C# 中,Infinity 是除以零時的結果。

  4. F5,或選取 [偵錯]>[繼續偵錯]

    Infinity 符號會出現在主控台中,作為數學運算的結果。

  5. 輸入 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;
        }
    }
}

下一步

恭喜您完成此教學課程! 若要深入了解,請繼續進行下列內容: