
C# 프로그램은 하나 이상의 파일로 구성됩니다. 각 파일은 0개 이상의 네임스페이스가 포함됩니다. 네임스페이스는 클래스, 구조체, 인터페이스, 열거형 및 대리자와 같은 형식이나 다른 네임스페이스를 포함합니다.
using System;
namespace YourNameSpace
{
class YourClass
{
}
struct YourStruct
{
}
interface IYourInterFace
{
}
delegate int YourDeleteGate();
enum YourEnum
{
}
namespace YourNestedNameSpace
{
struct YourStruct
{
}
}
}
앞의 예제에서는 프로그램의 진입점에 대해 최상위 문을 사용합니다. 다음 예제와 같이 프로그램의 진입점으로 Main이 라는 정적 메서드를 만들 수도 있습니다.
using System;
namespace YourNameSpace
{
class YourClass
{
}
struct YourStruct
{
}
interface IYourInterFace
{
}
delegate int YourDeleteGate();
enum YourEnum
{
}
namespace YourNestedNameSpace
{
struct YourStruct
{
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World");
}
}
}
1. Main()과 명령줄 인수
Main 메서드는 C# 애플리케이션의 진입점입니다.애플리케이션이 시작될 때 Main 메서드는 호출되는 첫 번째 메서드입니다. C# 프로그램에는 하나의 진입점만 있을 수 있습니다. Main 매서드가 있는 클래스가 둘 이상 있는 경우 StartupObject 컴파일러 옵션으로 프로그램을 컴파일해 진입점으로 사용할 Main 메서드를 지정해야 합니다.
class TestClass
{
static void Main(string[] args)
{
Console.WriteLine(args.Length);
}
}
한 파일의 최상위 문을 애플리케이션의 진입점으로 사용할 수도 있습니다. Main 매서드와 마찬가지로 최상위 문은 값을 반환하고 명령줄 인수에 액세스할 수 있습니다.
using System.Text;
StringBuilder builder = new();
builder.AppendLine("The following arguments are passed;");
foreach (var arg in args)
{
builder.AppendLine($"Argument={arg}");
}
Console.WriteLine(builder.ToString());
return 0;
Main 매서드는 실행 가능한 프로그램의 진입점으로, 프로그램의 제어가 시작되고 끝나는 위치입니다. 클래스 또는 구조체 내에서 선언되어야하며 바깥쪽 class는 static일 수 있습니다. Main은 액세스 한정자를 가질 수 있습니다(file 제외), void, int, Task 또는 Task<int> 반환 형식을 가질 수 있습니다.
Task 또는 Task<int> 를 반환하는 경우에만 Main 선언에 async 한정자가 포함될 수 있습니다. async void Main매서드를 제외합니다. Main 매서드는 명령줄 인수를 포함하는 string[] 매개 변수 사용 여부에 관계없이 선언될 수 있습니다.
Visual Studio를 사용하여 Windows 애플리케이션을 만드는 경우 매개 변수를 수동으로 추가하거나 GetCommandLineArgs() 매서드를 사용하여 명령줄 인수를 가져올 수 있습니다.
매개 변수는 0부터 시작하는 명령줄 인수로 읽힙니다. C및 C++ 와 달리, 프로그램 이름이 args 배열의 첫 번째 명령줄 인수로 처리되지 앉지만, GetCommandLineArgs() 메서드의 첫번째 요소입니다.
다음 목록에서는 가장 일반적인 Main 선언입니다.
static void Main() { }
static int Main() {}
static void Main(string[] args) { }
static int Main(string[] args) { }
static async Task Main() {}
static async Task<int> Main() {}
static async Task Main(string[] args) {}
static async Task<int> Main(string[] args) { }
2. Main() 반환 값
다음 방법 중 하나로 메서드를 정의해 Main 매서드에서 int를 반환할 수 있습니다.
| Main 선언 | Main 메서드 코드 |
| static int Main() | args 또는 await 사용 X |
| static int Main(string[] args) | args 사용, await 사용 X |
| static async Task<int> Main() | args 사용안함, await 사용 |
| static async Task<int> Main(string[] args) | args 및 await 사용 |
Main의 반환 값을 사용하지 않는 경우 void 또는 Task를 반환하면 코드가 다소 단순해집니다.
| Main 선언 | Main 메서드 코드 |
| static void Main() | args 또는 awiat 사용 X |
| static void Main(string[] args) | args 사용, await 사용X |
| static async Task Main() | args 사용X, await 사용 |
| static async Task Main(string[] args) | args 및 await 사용 |
그러나 int 또는 Task<int>를 반환하면 프로그램이 실행 파일을 호출하는 다른 프로그램이나 스크립트에 상태 정보를 전달할 수 있습니다. 다음 예제에서 프로세스의 종료 코드에 엑세스할 수 있는 방법을 보여줍니다.
이 예제에서는 .NET Core 명령줄 도구를 사용합니다. .NET Core 명령줄 도구에 대해 잘 모르는 경우 시작 문서에서 알아볼 수 있습니다.
dotnet new console을 실행해 새 어플리케이션을 만듭니다. Program.cs 에서 Main 매서드를 다음과 같이 수정합니다.
namespace ConsoleApp1
{
class MainReturnValTest
{
static int Main()
{
return 0;
}
}
}
Windows에서 프로그램을 실행하는 경우 Main 함수에서 반환된 값은 환경 변수에 저장됩니다. 이 환경 변수는 배치 파일에 ERRORLEVEL을 사용하거나 PowerShell 에서 $LastExitCode를 사용해 검색할 수 있습니다.
dotnet CLI의 dotnet build 명령어를 사용해 애플리케이션을 빌드할 수 있습니다.
다음으로 애플리케이션을 실행하고 결과를 표시하는 PowerSheel 스크립트를 만듭니다. 다음 코드를 텍스트 파일레 붙여넣고 이 파일을 프로젝트가 포함된 폴더에 test.ps1으로 저장합니다. PowerShell 프롬포트에 test.ps1을 입력해 PowerShell 스크립트를 실행합니다.
Execution succeeded
Return value = 0
3. 비동기 Main 반환 값
Main에 대한 async 반환 값을 선언하면 컴파일러는 Main에서 비동기 매서드를 호출하기 위한 상용구 코드를 생성합니다. async 키워드를 지정하지 않으면 다음 예와같이 해당 코드를 직접 작성해야 합니다.
class AsyncMainReturnValTest
{
public static int Main()
{
return AsyncConsoleWork().GetAwaiter().GetResult();
}
private static async Task<int> AsyncConsoleWork()
{
return 0;
}
}
이 상용구는 다음과 같이 변경할 수 있습니다.
class Program
{
//public static int Main()
static async Task<int> Main(string[] args)
{
//return AsyncConsoleWork().GetAwaiter().GetResult();
return await AsyncConsoleWork();
}
private static async Task<int> AsyncConsoleWork()
{
return 0;
}
}
Main을 async로 선언하면 컴파일러가 항상 올바를 코드를 생성한다는 이점이 있습니다. 애플리케이션 진입점에서 Task 또는 Task<int>를 반환하는 경우 컴파일러는 애플리케이션 코드에서 선언된 진입점 메서드를 호출하는 새 진입점을 생성합니다. 이 진입점에서 $GeneratedMain이라고 가정하면 컴파일러는 이러한 진입점에 대하 다음 코드를 생성합니다.
- static Task Main() - 컴파일러에서 private static void $GeneratedMain() => Main().GetAwaiter().GetResult();에 해당하는 코드를 내보냅니다.
- static Task Main(string[]) - 컴파일러에서 private static void $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();에 해당하는 코드를 내보냅니다.
- static Task<int> Main() - 컴파일러에서 private static int $GeneratedMain() => Main().GetAwaiter().GetResult();에 해당하는 코드를 내보냅니다.
- static Task<int> Main(string[]) - 컴파일러에서 private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();에 해당하는 코드를 내보냅니다.
명령줄 인수
다음 방법 중 하나로 매서드를 정의하여 인수를 Main 메서드에 보낼 수 있습니다.
| Main 선언 | Main 매서드 코드 |
| static void Main(string[] args) | 반환 값 없음, await X |
| static int Main(string[] args) | 반환 값, awiat 사용 X |
| static async Task Main(string[] args) | 반환 값 X, awiat 사용 O |
| static async Task<int>(string[] args) | 반환 값, await 사용 O |
인수가 사용되지 않은 경우 약간 더 간단한 코드로 매서드 선언에서 args 를 생략할 수 있습니다.
| Main 선언 | Main 매서드 코드 |
| static void Main() | 반환 값 없음, await 사용 X |
| static int Main() | 반환 값, await 사용 X |
| static async Task Main() | 반환 값 X, await 사용 |
| static async Task<int> Main() | 반환 값 await 사용 |
Main 매서드의 매개 변수는 명령줄 인수를 나타내는 String 배열입니다. 일반적으로 다음과 같이 Length 속성을 테스트하여 인수가 있는지 확인합니다.
if (args.Length == 0)
{
System.Console.WriteLine("Please enter a numeric argument.");
return 1;
}
Convert 클래스 또는 Parse 매서드를 사용하여 문자열 인수를 숫자 형식으로 변환할 수도 있습니다. 예를 들어 Parse 매서드를 활용해 string 을 long 숫자로 변환 합니다.
long num = Int64.Parse(args[0]);
Int64의 별칭을 지정하는 C# 형식 long을 사용할 수 있습니다.
long num = long.Parse(args[0]);
long num = Convert.ToInt64(s);
Convert 클래스 매서드 ToInt64를 사용해 같은 작업을 수행할 수 있습니다. 다음 예제로 콘솔 애플리케이션에서 명령줄 인수를 사용하는 방법을 보여줍니다. 애플리케이션은 런타임에 하나의 인수를 사용하고, 인수를 정수로 변환하고, 숫자의 계승을 계산합니다. 인수가 제공되지 않으면 애플리케이션에서는 프로그램의 올바른 사용법을 설명하는 메시지를 표시합니다.
명령 프롬프트에서 애플리케이션을 컴파일 실행하려면 다음단계를 수행합니다.
- 다음 코드를 텍스트 편집기에 붙여넣고 이름 Factorial.cs로 사용하여 파일을 텍스트 파일로 저장합니다.
public class Functions
{
public static long Factorial(int n)
{
if ((n < 0) || (n > 20))
{
return -1;
}
long tempResult = 1;
for (int i = 1; i <= n; i++)
{
tempResult *= i;
}
return tempResult;
}
}
class MainClass
{
static int Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Please enter a numeric argument");
Console.WriteLine("Usage: Factorial <num>");
return 1;
}
int num;
bool test = int.TryParse(args[0], out num);
if (!test)
{
Console.WriteLine("Please enter a numeric argument.");
Console.WriteLine("Usage: Factorial <num>");
return 1;
}
long result = Functions.Factorial(num);
if (result == 1)
Console.WriteLine("Input must be >= 0 and <= 20");
else
Console.WriteLine($"The Factorial of {num} is {result}.");
return 0;
}
}
시작 화면이나 시작 메뉴에서 Visual Studio 개발자 명령 프롬프트 창을 열고 만든 파일이 포함된 폴더로 이동합니다. 다음 명령을 입력해 애플리케이션을 컴파일합니다.
dotnet build
애플리케이션에 컴파일 오류가 없다면 Factorial.exe라는 실행 파일이 만들어집니다. 다음 명령을 입력해 3의 계승을 계산합니다.
dotnet run --3
Main()과 명령줄 인수 - C#
Main()과 명령줄 인수에 대해 알아봅니다. ‘Main’ 메서드는 실행 가능한 프로그램의 진입점입니다.
learn.microsoft.com
4. 최상위 문 - Main 매서드가 없는 프로그램
콘솔 애플리케이션 프로젝트에 Main 매서드를 명시적으로 포함할 필요가 없습니다. 대신 최상위 문 기능을 사용하여 작성해야 하는 코드를 최소화할 수 있습니다. 최상위 문을 사용하면 파일의 루트에 직접 실행 코드를 작성할 수 있으므로 클래스 또는 메서드에서 코드를 래핑할 필요가 없습니다.
따라서 Program 클래스 및 Main 메서드의 형식 없이 프로그램을 만들 수 있습니다. 이 경우 컴파일러는 애플리케이션에 대한 진입점 메서드를 사용하여 Program 클래스를 생성합니다. 생성된 메서드의 이름은 Main이 아니며 코드에서 직접 참조할 수 없는 구현 세부 정보입니다.
Console.WriteLine("Hello World!");
최상위 문을 사용하면 Azura Functions 및 GitHub Actions와 같은 소규모 유틸리티에 대한 간다한 프로그램을 작성할 수 있습니다. 또한 새로운 C# 프로그래머가 코드를 학습하고 작성하는 작업을 더 쉽게 수행할 수 있습니다.
하나의 최상위 파일만
애플리케이션에는 진입점이 하나만 있어야 합니다. 프로젝트에는 최상위 문이 있는 파일이 하나만 있을 수 있습니다. 프로젝트의 두 개 이상의 파일에 최상위 문을 넣으면 다음과 같은 컴파일러 오류가 발생합니다.
CS8802 하나의 컴파일 단위만 최상위 문을 포함할 수 있습니다.
프로젝트에 최상위 문이 없는 소스 코드 파일은 얼마든지 포함될 수 있습니다.
다른 진입점 없음
Main 메서드를 명시적으로 작성할 수 있으나 진입점으로는 작동할 수 없습니다. 컴파일러에서 다음과 같은 경고가 발생합니다.
CS7022 프로그램의 진입점은 전역 코드이며 'Main()' 진입점은 무시됩니다.
최상위 문이 있는 프로젝트에서 프로젝트 하나 이상의 메서드가 있는 경우에도 Main 컴파일러 옵션을 사용해 진입점을 선택할 수 없습니다.
using 지시문
지시문을 포함하는 using 경우 다음 예제와 같이 파일에서 먼저 와야 합니다.
using System.Text;
StringBuilder builder = new();
builder.AppendLine("The following arguments are passed:");
foreach (var arg in args)
{
builder.AppendLine($"Argument={arg}");
}
Console.WriteLine(builder.ToString());
return 0;
전역 네임스페이스
최상위 문은 전역 네임스페이스에서 암시적으로 사용할 수 있습니다.
네임스페이스 및 형식 정의
최상위 문이 있는 파일에는 네임스페이스 및 형식 정의도 포함될 수 있으나 최상위 문 뒤에 와야합니다.
MyClass.TestMethod();
MyNamespace.MyClass.MyMethod();
public class MyClass
{
public static void TestMethod()
{
Console.WriteLine("Factory!");
}
}
namespace MyNamespace
{
class MyClass
{
public static void MyMethod()
{
Console.WriteLine("Hello World from MyNameSpace.MyClass.MyMethod Welcome!");
}
}
}
args
최상위 문은 args 변수를 참조해 입력된 명령줄 인수에 액세스할 수 있습니다. args 변수는 null이 아니지만 명령줄 인수가 제공되지 않은 경우 Length는 0입니다.
if (args.Length > 0)
{
foreach (var arg in args)
{
Console.WriteLine($"Argument={arg}");
}
} else
{
Console.WriteLine("No arguments");
}
await
await를 사용해 비동기 메서드를 호출할 수 있습니다.
Console.Write("MayDay");
await Task.Delay(5000);
Console.WriteLine("Help");
프로세스의 종료 코드
애플리케이션이 종료될 때 int 값을 반환하려면 return을 반환하는 Main 매서드에서와 같이 int 문을 사용합니다.
string? s = Console.ReadLine();
int returnValue = int.Parse(s ?? "-1");
return returnValue;
암시적 진입점 메서드
컴파일러는 최상위 문이 있는 프로젝트의 프로그램 진입점 역할을 하는 메서드를 생성합니다. 메서드의 서명은 최상위 문에 await 키워드 또는 return 문이 포함되 있는지 여부에 따라 달라집니다.
| 최상위 코드에는 다음이 포함 | 암시적 Main 서명 |
| await 및 return | static async Task<int> Main(string[] args) |
| await | static async Task Main(string[] args) |
| return | static int Main(string[] args) |
| await or return X | static void Main(string[] args) |
GitHub - Koras02/project
Contribute to Koras02/project development by creating an account on GitHub.
github.com
C# 프로그램의 일반적인 구조체 - C#
C# 프로그램에 필요한 모든 요소를 포함하는 기본 구조 프로그램을 사용하여 프로그램 구조에 대해 알아봅니다.
learn.microsoft.com
'게임 모딩 > C#' 카테고리의 다른 글
| [C#] 8.C#의 네임스페이스, 클래스, 레코드, 인터페이스, 제네릭, 익명 형식 (0) | 2025.02.03 |
|---|---|
| [C#] 7. C#의 형식 시스템 (0) | 2025.01.27 |
| [C#] 5.목록 형식을 사용한 데이터 컬렉션 관리 (0) | 2025.01.26 |
| [C#] 4.분기 및 루프 문이 포함된 조건문 (0) | 2025.01.26 |
| [C#] 3. 정수 및 부동 소수점 수 조작 (0) | 2025.01.25 |