4. Console Application 추가사항
Console형식의 App은 화려하고 편리한 GUI를 지원하지는 않지만 간단하게 특정 기능을 테스트하고 코드를 학습하기 위한 좋은 선택이 될 수 있으며 이미 이전의 예제에서 Console프로젝트를 생성해 사용해 왔습니다.
하지만 때로는 Console상에서 어떤 결과를 출력할 때 다소 불편한 상황이 전개될 수 있는데 이를 위해 몇 가지 보완할 수 있는 방법을 알아보고자 합니다.
● 번호가 매겨진 선택적 매개변수의 사용 (numbered positional arguments)
'numbered positional arguments'는 Write()나 WriteLine() 메서드를 통해 문자열을 출력하는 경우 특정 포맷으로 형식화할 수 있는 방법 중에 하나가 될 수 있으며 출력을 위한 메서드가 아니라 하더라도 string자체에서 Format()라는 메서드를 사용해 형식화를 수행할 수도 있습니다.
int i = 12;
int j = 34;
Console.WriteLine(format:"i : {0}, j : {1}", arg0: i, arg1: j * 3);
//string의 format
string s = string.Format(format:"i : {0}, j : {1}", arg0: i, arg1: j * 3);
Console.WriteLine(s);
● 보간 문자열 사용
'numbered positional arguments'는 형식화에서 각각의 인수가 어떤 순서로 처리되는지를 설명하기 위한 것으로 실무에서는 보간 문자열을 사용한 형식화를 사용하는 것이 좋습니다.
int i = 12;
int j = 34;
Console.WriteLine($"i : {i}, j : {j * 3}");
보간 문자열은 문자열 앞에 $접두사를 붙여 사용하는 것으로 변수나 식에 arg0, arg1처럼 순서를 붙이는 대신 중괄호를 감싸 원하는 형식으로 출력할 수 있도록 합니다.
변수나 식에 중괄호를 붙여 사용하는 방식은 C#10에서 문자열 결합을 간소화하는데도 사용할 수 있습니다. 예를 들어 C#10 이전에 문자열 결합을 위해서 아래와 같이 했다면
string a = "abc";
string b = "def";
string c = a + b;
Console.WriteLine(c);
C#10에서는 변수에 중괄호만 붙여주면 원하는 결과를 얻을 수 있습니다.
string a = "abc";
string b = "def";
string c = $"{a}{b}";
Console.WriteLine(c);
※ 보간 문자열이나 numbered positional arguments모두 문자열 그대로를 literal로 사용하는 것보다는 성능상 불리한 점이 있습니다.
● 문자열 형식화
이전 예제에서처럼 변수나 식은 문자열 형식화를 통해 편리하게 해당 결과를 문자열에 섞어 표현할 수 있었습니다. 여기에 더해 콤마(,)와 콜론(:)을 사용하여 좀 더 풍부한 형식화를 구현할 수 있습니다.
예를 들어 N0은 특정 수를 천 단위로 구분하여 표시함을 의미하며 C는 현재 설정된 지역에 맞는 통화(Currency) 표현을 의미합니다. 이러한 의미론적인 기능을 문자열 형식화를 통해 표현하게 되면 다음과 같이 구현할 수 있습니다.
int i = 123456789;
int m = 1000;
//상품갯수 : 123,456,789, 상품별단가 : \1,000
Console.WriteLine($"상품갯수 : {i:N0}, 상품별단가 : {m:C}");
※ 본래 \와 \문자는 같은 표현임에 주의하세요.
콤마(,)를 사용하여 형식화하는 경우는 전체 공간에서 정렬 방식을 지정하는 것으로 예를 들어 20은 전체 20자리에서 왼쪽 정렬을, -20은 전체 20자리에서 오른쪽 정렬을 의미합니다.
//A상품갯수 : 123,456,789 , 상품별단가 : \1,000
//A상품갯수 : 123,000 , 상품별단가 : \2,000
int ai = 123456789;
int am = 1000;
Console.WriteLine($"A상품갯수 : {ai,-20:N0}, 상품별단가 : {am,10:C}");
int bi = 123000;
int bm = 2000;
Console.WriteLine($"A상품갯수 : {bi,-20:N0}, 상품별단가 : {bm,10:C}");
● 사용자 입력 처리
Console에서 사용자에게 어떤 값을 출력하기 위해 Write()나 WriteLine() 메서드를 사용했는데 반대로 입력값을 얻으려면 Read()나 ReadLine()을 사용할 수 있습니다.
//이름을 입력해 주세요. : 홍길동
//귀하의 이름은 : 홍길동 입니다.
string? sName = string.Empty;
Console.Write("이름을 입력해 주세요. : ");
sName = Console.ReadLine();
Console.WriteLine($"귀하의 이름은 : {sName} 입니다.");
Read()나 ReadLine()은 사용자가 Enter키를 먹일 때까지 입력을 대기하는 메서드입니다. 따라서 원하는 내용을 텍스트로 입력하고 Enter키를 누르게 되면 그때까지 입력된 내용을 처리할 수 있게 되는 것입니다. 단, Read()는 단 한문자의 입력값만을 다룰 수 있다는 차이가 있습니다.
Read()나 ReadLine()처럼 입력을 받는 메서드로 ReadKey()라는 메서드도 존재합니다. 이 메서드는 문자열 값이 아닌 사용자의 키 입력을 받는 메서드로 키 혹은 Alt 같은 다른 키와 결합된 키의 입력이 발생하면 그 즉시 ConsoleKeyInfo형식의 값을 반환합니다.
//키입력 대기중...
//c입력된 키는 다음과 같습니다.
//Key: C, Char: c, Modifiers: Alt
Console.WriteLine("키입력 대기중...");
ConsoleKeyInfo ki = Console.ReadKey();
Console.WriteLine("입력된 키는 다음과 같습니다.");
Console.WriteLine($"Key: {ki.Key}, Char: {ki.KeyChar}, Modifiers: {ki.Modifiers}");
● 정적(static) import
System.Console는 정적 클래스이며 using구문을 사용하면 이러한 정적 클래스를 Import 할 수 있게 됩니다. 그러면 실제 Code작성 시 Console.WriteLine()처럼 매번 정적 클래스명을 붙여주는 방식에서 벗어나 간단히 WriteLine()처럼 메서드만 작성할 수 있게 됩니다.
using static System.Console;
WriteLine("abc");
● 매개변수 전달
Console Application에서 추가적으로 전달된 매개변수는 args라는 string형식의 Array로부터 읽을 수 있습니다.
//dotnet run aaa bbb
//전달된 값 : aaa
//전달된 값 : bbb
foreach(string s in args)
{
Console.WriteLine($"전달된 값 : {s}");
}
본래 .NET6이전에 Console Application의 템플릿은 다음과 같은 형태를 이루고 있었습니다.
class TestClass
{
static void Main(string[] args)
{
}
}
Console Application이 시작되면 제일 처음 Main메서드로 Program실행이 시작되며 이때 args로 입력된 매개변수가 전달되는 것입니다. .NET6부터는 Top-level program형태로 상기 템플릿 전체가 숨겨진 형태로 만들어지게 되었습니다. 다만 이것은 숨겨진 것이지 사라진 것이 아니기 때문에 매개변수로 만들어진 args는 여전히 사용이 가능한 것입니다.
참고로 매개변수는 공백으로 구분됩니다. 만약 인수 자체가 공백을 포함해야 한다면 큰따옴표(")로 문자열을 감싸서 전달해야 합니다.
C:\Users\Administrator\Downloads\csharp>dotnet run "aaa bbb" ccc
전달된 값 : aaa bbb 전달된 값 : ccc C:\Users\Administrator\Downloads\csharp> |
● 특정 OS에서 지원되지 않는 API 처리하기
.NET은 크로스 플랫폼을 기반으로 하기 때문에 Windows나 MacOS, Linux에서 실행될 수 있습니다. 하지만 .NET의 모든 API가 모든 OS상에서 실행되기를 기대할 수 없는 경우도 있기 때문에 이에 대한 예외적인 처리를 해야 하는 경우가 있습니다.
일반적으로는 try ~ catch구문을 사용할 수 있는데
try {
}
catch (PlatformNotSupportedException)
{
Console.WriteLine("해당 OS상에서는 지원되지 않는 기능입니다.");
}
처음부터 OS별 구분이나 플랫폼 구분이 필요하다면 System Namespace에 있는 OperatingSystem클래스를 사용할 수 있습니다.
if (OperatingSystem.IsWindows())
{
//윈도우에서 실행되는 경우
}
else if (OperatingSystem.IsWindowsVersionAtLeast(major: 10))
{
//특정 윈도우 버전을 구분해야 하는 경우
}
else if (OperatingSystem.IsLinux())
{
//리눅스에서 실행되는 경우
}
else if (OperatingSystem.IsIOSVersionAtLeast(major: 14, minor: 5))
{
//IOS(14.5)에서 실행되는 경우
}
else if (OperatingSystem.IsBrowser())
{
//브라우저에서 실행되는 경우
}
예제에서는 5가지 정도를 사용했는데 이 외에 더 많은 메서드를 지원하므로 필요하다면 해당 환경에 맞는 다른 메서드를 사용할 수도 있습니다.
또한 다른 방법으로는 조건부 컴파일 구문(conditional compilation statements)을 사용하는 것입니다.
보통 전처리를 위해 #define을 사용하여 임의로 symbol을 지정할 수 있는데 이미 .NET에는 플랫폼을 구분하기 위한 전처리로 NET6_0, NET6_0_ANDROID, NET6_0_IOS, NET6_0_WINDOWS 등이 마련되어 있습니다. 따라서 다음과 같이 특정 플렛폼을 구분하기 위한 처리를 구현할 수 있습니다.
#if NET6_0_ANDROID
// Android 실행
#elif NET6_0_IOS
// IOS 실행
#else
// 그외
#endif
'.NET > C#' 카테고리의 다른 글
[C#] 흐름제어 (0) | 2022.06.24 |
---|---|
[C#] 연산자 (0) | 2022.06.24 |
[C#] C# 개요 - 2. 변수 (0) | 2022.06.24 |
[C#] C# 개요 - 1. C#의 특징및 개요 (0) | 2022.06.24 |
[C#] C#과 .NET6 시작하기 - 3. Console App 만들어 보기 (0) | 2022.06.24 |