다음을 통해 공유


자습서: Visual Studio에서 C# 콘솔 앱 및 디버그 확장(2부)

이 자습서 시리즈의 2부에서는 매일 개발하는 데 필요한 Visual Studio 빌드 및 디버그 기능을 좀 더 자세히 살펴봅니다. 이러한 기능에는 여러 프로젝트 관리, 디버깅 및 타사 패키지 참조가 포함됩니다. 이 자습서 1부에서 만든 C# 콘솔 앱을 실행하고 Visual Studio IDE(통합 개발 환경)의 일부 기능을 살펴봅니다. 이 자습서는 2부로 구성된 자습서 시리즈의 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.csCalculator 클래스와 해당 코드를 모두 선택하고 Ctrl+X 눌러 잘라냅니다. 그런 다음 CalculatorLibrary.cs코드를 CalculatorLibrary 네임스페이스에 붙여넣습니다.

    또한 계산기 클래스 앞에 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 다른 네임스페이스에 있기 때문입니다. 정규화된 참조의 경우 CalculatorLibraryCalculator.DoOperation 호출에 네임스페이스를 추가할 수 있습니다.

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

    또는 using 파일의 시작 부분에 지시문을 추가해 볼 수 있습니다.

    // Program.cs
    using CalculatorLibrary;
    

    using 지시문을 추가하면 호출 사이트에서 CalculatorLibrary 네임스페이스를 제거할 수 있지만 이제 모호성이 있습니다. Calculator CalculatorLibrary클래스인가요, 아니면 네임스페이스에 Calculator 있나요?

    모호성을 해결하려면 네임스페이스의 이름을 Calculator에서 CalculatorProgram으로 Program.cs파일에서 변경하세요.

    // 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.csCalculator 클래스와 해당 코드를 모두 선택하고 Ctrl+X 눌러 잘라냅니다. 그런 다음 CalculatorLibrary.cs코드를 CalculatorLibrary 네임스페이스에 붙여넣습니다.

    또한 계산기 클래스 앞에 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 다른 네임스페이스에 있기 때문입니다. 정규화된 참조의 경우 CalculatorLibraryCalculator.DoOperation 호출에 네임스페이스를 추가할 수 있습니다.

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

    또는 using 파일의 시작 부분에 지시문을 추가해 볼 수 있습니다.

    // Program.cs
    using CalculatorLibrary;
    

    using 지시문을 추가하면 호출 사이트에서 CalculatorLibrary 네임스페이스를 제거할 수 있습니다.

    Program.cs 코드가 Calculator 네임스페이스에 있는 경우 네임스페이스의 이름을 CalculatorCalculatorProgram 이름을 바꿔 클래스 이름과 네임스페이스 이름 간의 모호성을 제거합니다.

.NET 라이브러리 참조: 로그에 쓰기

.NET Trace 클래스를 사용하여 모든 작업의 로그를 추가하고 텍스트 파일에 쓸 수 있습니다. Trace 클래스는 기본 인쇄 디버깅 기술에도 유용합니다. Trace 클래스는 System.Diagnostics있으며 System.IO같은 StreamWriter 클래스를 사용합니다.

  1. 먼저 using맨 위에 지시문을 추가합니다.

    // 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.IO같은 StreamWriter 클래스를 사용합니다.

  1. 먼저 using맨 위에 지시문을 추가합니다.

    // 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으로 작업을 출력하려면 Newtonsoft.Json NuGet 패키지를 참조할 수 있습니다. 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. JSON DoOperation 코드를 추가하도록 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입력합니다.

    앱은 중단점을 만든 위치를 일시 중단합니다. 중단점은 왼쪽의 노란색 포인터와 강조 표시된 코드로 표시됩니다. 강조 표시된 코드가 아직 실행되지 않았습니다.

    중단점에 도달한 스크린샷Screenshot of hitting a breakpointScreenshot of hitting a breakpoint

    이제 앱이 일시 중단되면 애플리케이션 상태를 검사할 수 있습니다.

디버그: 변수 보기

  1. 강조 표시된 코드에서 cleanNum1op같은 변수를 마우스로 가리킵니다. 이러한 변수의 현재 값(각각 8d)이 DataTips에 표시됩니다.

    DataTip 보기를 보여 주는 스크린샷

    디버깅할 때 변수에 예상한 값이 있는지 여부를 확인하는 것이 문제 해결에 중요한 경우가 많습니다.

  2. 아래쪽 창에서 Locals 창을 살펴봅니다. 닫힌 경우 디버그>Windows>로컬 선택하여 엽니다.

    Locals 창에는 현재 범위에 있는 각 변수와 해당 값 및 형식이 표시됩니다.

    로컬 창의 스크린샷

    로컬 창의 스크린샷

  3. 자동 창을 살펴봅니다.

    자동 창은 Locals 창과 비슷하지만 앱이 일시 중지된 현재 코드 줄 바로 앞과 다음의 변수를 표시합니다.

    메모

    자동 창이 표시되지 않으면 디버그>Windows>자동 선택하여 엽니다.

다음으로 디버거에서 한 번에 하나의 명령문을 실행합니다. 이를 단계별호출합니다.

디버그: 코드 단계별 실행

  1. F11를 누르거나 디버그>한 단계씩 들어가기를 선택합니다.

    Step Into 명령을 사용하여 앱은 현재 문을 실행하고 다음 실행 문(일반적으로 다음 코드 줄)으로 진행합니다. 왼쪽의 노란색 포인터는 항상 현재 구문을 나타냅니다.

    명령 단계별 스크린샷

    방금 DoOperation 클래스의 Calculator 메서드에 들어갔습니다.

  2. 프로그램 흐름을 계층적으로 살펴보려면 호출 스택 창을 확인합니다. 닫혀 있는 경우에는 디버그>Windows>호출 스택을(를) 선택하여 엽니다.

    호출 스택의 스크린샷

    이 보기는 노란색 포인터로 표시된 현재 Calculator.DoOperation 메서드를 보여줍니다. 두 번째 행에는 Main 메서드에서 메서드를 호출한 함수가 표시됩니다.

    호출 스택 창에는 메서드 및 함수가 호출되는 순서가 표시됩니다. 또한 이 창은 바로 가기 메뉴에서 소스 코드이동과 같은 많은 디버거 기능에 액세스할 수 있습니다.

  3. 문에서 앱이 일시 중지될 때까지 여러 번 F10을 누르거나, >switch을 선택합니다.

    // CalculatorLibrary.cs
    switch (op)
    {
    

    Step Over 명령은 현재 문이 함수를 호출하는 경우 디버거가 함수에서 코드를 실행하고 함수가 반환될 때까지 실행을 일시 중단하지 않는다는 점을 제외하고 Step Into 명령과 유사합니다. 관심이 없는 특정 함수가 있을 경우, 'Step Over'는 'Step Into'보다 더 빠릅니다.

  4. 앱이 다음 코드 줄에서 일시 중지되도록 F10 한 번 더 누릅니다.

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

    이 코드는 0으로 나누는 경우를 점검합니다. 앱이 계속되면 일반적인 예외(오류)가 throw되지만 콘솔에서 실제 반환된 값을 보는 것과 같은 다른 작업을 시도할 수 있습니다. 한 가지 옵션은 편집 및 계속 디버거 기능을 사용하여 코드를 변경한 다음 디버깅을 계속하는 것입니다. 그러나 실행 흐름을 일시적으로 수정하는 다른 트릭이 있습니다.

디버그: 임시 변경 테스트

  1. 현재 if (num2 != 0) 문에서 일시 중지된 노란색 포인터를 선택하고 다음 문으로 끕니다.

    // CalculatorLibrary.cs
    result = num1 / num2;
    

    여기서 포인터를 끌면 앱이 if 문을 완전히 건너뛰므로 0으로 나눌 때 어떤 일이 발생하는지 확인할 수 있습니다.

  2. F10 눌러 코드 줄을 실행합니다.

  3. result 변수를 마우스로 가리키면 무한대값이 표시됩니다. C#에서 무한대는 0으로 나눌 때의 결과입니다.

  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;
        }
    }
}

다음 단계

이 자습서를 완료해 주셔서 감사합니다. 자세히 알아보려면 다음 콘텐츠를 계속 진행하세요.