共用方式為


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

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

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

  • 新增第二個專案。
  • 引用程式庫並新增套件。
  • 對程式代碼進行偵錯。
  • 檢查已完成的程序代碼。

先決條件

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

新增另一個專案

實務上的程式碼涉及專案在一個方案中共同運作。 您可以將類別庫專案新增至計算機應用程式,以提供一些計算機函式。

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

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

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

    類別庫專案範本選取項目的螢幕快照。

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

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

    [方案總管] 的螢幕快照,其中已新增 CalculatorLibrary 類別庫專案。

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

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

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

    [新增項目參考] 選單項目的螢幕快照。

    [參考管理員] 對話框隨即出現。 在此對話框中,您可以新增專案所需的其他專案、程式集和 COM DLL 的參考。

  7. 在 [參考管理員] 對話框中,選取 CalculatorLibrary 項目的複選框,然後選取 [確定]

    [參考管理員] 對話框的螢幕快照。

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

    方案總管的螢幕快照,其中包含項目參考。

  8. 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;
             }
         }
     }
    
  9. 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 命名空間,但現在出現了歧義。 CalculatorCalculatorLibrary中的類別,還是 Calculator 是命名空間?

    若要解決模棱兩可的情況,請將命名空間從 Calculator 重新命名為 CalculatorProgram中的

    // Program.cs
    namespace CalculatorProgram
    
  1. 在 [方案總管]中,以滑鼠右鍵按兩下方案節點,然後選擇 [新增>新增專案]

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

    類別庫專案範本選取項目的螢幕快照。

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

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

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

    [方案總管] 的螢幕快照,其中已新增 CalculatorLibrary 類別庫專案。

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

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

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

    [新增項目參考] 選單項目的螢幕快照。

    [參考管理員] 對話框隨即出現。 在此對話框中,您可以新增專案所需的其他專案、程式集和 COM DLL 的參考。

  7. 在 [參考管理員] 對話框中,選取 CalculatorLibrary 項目的複選框,然後選取 [確定]

    [參考管理員] 對話框的螢幕快照。

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

    方案總管的螢幕快照,其中包含項目參考。

  8. 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;
             }
         }
     }
    
  9. 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.IOStreamWriter 類別。

  1. 從將 using 指令新增到 CalculatorLibrary.cs的頂端開始:

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

    // Program.cs
    Calculator calculator = new Calculator();
    

    同時修改 DoOperation 呼叫位置,以小寫形式參照名為 calculator 的物件。 程式代碼現在是成員調用,而不是對靜態方法的呼叫。

    // Program.cs
    result = calculator.DoOperation(cleanNum1, cleanNum2, op);
    
  5. 再次執行應用程式。 完成後,使用滑鼠右鍵點擊 [計算機] [] 專案節點,然後選擇 [在檔案總管中開啟資料夾] []。

  6. 在 [檔案總管] 中,流覽至 [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.IOStreamWriter 類別。

  1. 從將 using 指令新增到 CalculatorLibrary.cs的頂端開始:

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

    // Program.cs
    Calculator calculator = new Calculator();
    

    同時修改 DoOperation 呼叫位置,以小寫形式參照名為 calculator 的物件。 程式代碼現在是成員調用,而不是對靜態方法的呼叫。

    // Program.cs
    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 應該類似下列程序代碼:

// 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 類別庫的主要散發方法。

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

    快捷方式功能表上 [管理 NuGet 套件] 的螢幕快照。

    快捷方式功能表上 [管理 NuGet 套件] 的螢幕快照。

    NuGet 套件管理員隨即開啟。

    NuGet 套件管理員的螢幕快照。

  2. 搜尋並選取 Newtonsoft.Json 套件,然後選取「安裝」。

    NuGet 套件管理員中 Newtonsoft J SON NuGet 套件資訊的螢幕快照。

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

    NuGet 套件管理員中 Newtonsoft J SON NuGet 套件資訊的螢幕快照。

    如果系統提示您是否接受變更,請選擇 [確定]

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

    using開頭,新增 Newtonsoft.Json 指令以供 使用。

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

         // 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;
         }
    
  5. 新增方法以在使用者完成輸入作業數據之後完成 JSON 語法。

     // CalculatorLibrary.cs
     public void Finish()
     {
         writer.WriteEndArray();
         writer.WriteEndObject();
         writer.Close();
     }
    
  6. Program.cs結尾,於 return;之前,添加一個呼叫至 Finish

         // Program.cs
             // 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,或以滑鼠右鍵點選該行,然後選取 [斷點],>[插入斷點]

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

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

    顯示設定斷點的螢幕快照。

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

    • 在第一個數位中,輸入 8
    • 針對第二個數字,輸入 0
    • 對於操作員,讓我們來點樂子。 輸入 d

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

    觸發斷點的螢幕快照

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

偵錯:檢視變數

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

    顯示檢視 DataTip 的螢幕快照。

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

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

    [局部變數] 視窗會顯示當前作用域中的每個變數,以及它們的值和類型。

    本地視窗的螢幕快照。

    本地視窗的螢幕快照。

  3. 查看 [自動] 視窗。

    [自動變數] 視窗與 [局部變數] 視窗相似,但會顯示在應用程式暫停時,程式代碼行前後的變數。

    注意

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

接下來,在調試器中逐步執行程式碼語句,這被稱為單步執行

偵錯:逐步執行程式碼

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

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

    逐步執行命令的截圖

    您剛進入 DoOperation 方法中的 Calculator 類別。

  2. 若要以階層方式檢視程式流程,請查看 [呼叫堆疊] 視窗。 如果已關閉,請選取 偵錯>Windows>呼叫堆疊 將其開啟。

    呼叫堆疊 的螢幕快照

    此檢視會顯示目前 Calculator.DoOperation 方法,以黃色指標表示。 第二列顯示 Main中的 方法,這個方法是由該函式呼叫的。

    呼叫堆疊 視窗會顯示呼叫方法和函式的順序。 此視窗也可從其快捷方式功能表存取許多調試程式功能,例如 移至原始程式碼

  3. F10,或重複選取 [偵錯]>[逐步執行],直到應用程式暫停在 switch 語句上。

    // CalculatorLibrary.cs
    switch (op)
    {
    

    Step Over 命令類似於 [逐步執行] 命令,不同之處在於,如果目前的語句呼叫函式,調試器會運行該函式中的代碼,並且在函式返回之前不會暫停執行。 如果您對特定函式不感興趣,則「略過」比「進入」更快。

  4. 再按 F10 一次,讓應用程式在下列程式代碼行暫停。

    // CalculatorLibrary.cs
    if (num2 != 0)
    {
    

    此程式代碼會檢查零除大小寫。 如果應用程式繼續運行,它會拋出一般例外狀況(錯誤),但你可能想嘗試其他方法,例如在控制台查看實際返回的值。 其中一個選項是使用稱為 編輯後繼續 的調試程式功能來變更程式代碼,然後繼續偵錯。 不過,暫時修改執行流程有另一種技巧。

偵錯:測試暫時性變更

  1. 選取目前在 if (num2 != 0) 語句上暫停的黃色指標,並將其拖曳至下列語句:

    // CalculatorLibrary.cs
    result = num1 / num2;
    

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

  2. F10 以執行程式碼行。

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

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

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

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

後續步驟

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