본문 바로가기
프로그래밍/C#

C# Discards _의 정체

by bantomak 2023. 3. 23.

Discards _ 란

C#에서는 어플리케이션에서 의도적으로 사용되지 않는 임시 변수인 Discards를 제공한다.

Discards 변수는 "_" (underscore, 언더스코어 혹은 underbar, 언더바)로 표시한다.

 

왜 무시 변수인 Discard가 필요한가?

  • 별도의 변수를 선언 할 필요가 없다. 또한 discards를 사용하면 메모리 할당을 줄일 수 있다.
  • 코드의 의도를 투명하게 만들고 가독성과 유지 관리성을 향상시키는데 도움이 된다.

 

예제 코드

  • switch를 사용한 패턴 매칭
class Program
{
    static void ProvideString(string statement) =>
        Console.WriteLine(statement switch
        {
            "x" => "hello, x world",
            null => "hello, null world",
            _ => "hello, world"
        });


    static void Main(string[] args)
    {
        ProvideString("x");
        ProvideString(null);
        ProvideString("");
    }
}

정의되지 않은 형식에 대해서는 모두 _로 대응이 가능하다.

 

  • out 매개 변수를 사용한 메서드 호출
string[] dateStrings = {"05/01/2018 14:57:32.8", "2018-05-01 14:57:32.8",
                      "2018-05-01T14:57:32.8375298-04:00", "5/01/2018",
                      "5/01/2018 14:57:32.80 -07:00",
                      "1 May 2018 2:57:32.8 PM", "16-05-2018 1:00:32 PM",
                      "Fri, 15 May 2018 20:10:57 GMT" };
foreach (string dateString in dateStrings)
{
    if (DateTime.TryParse(dateString, out _))
        Console.WriteLine($"'{dateString}': valid");
    else
        Console.WriteLine($"'{dateString}': invalid");
}

dateString의 유효성만을 확인하고 싶고 out 인수를 무시하고 싶을때 사용하면 유용하다.

별도의 변수를 생성하고 이를 인자로 설정하지 않아도 된다.

 

  • 독립 실행형 무시 항목
private static async Task ExecuteAsyncMethods()
{
    Console.WriteLine("About to launch a task...");
    _ = Task.Run(() =>
    {
        var iterations = 0;
        for (int ctr = 0; ctr < int.MaxValue; ctr++)
            iterations++;
        Console.WriteLine("Completed looping operation...");
        throw new InvalidOperationException();
    });
    await Task.Delay(5000);
    Console.WriteLine("Exiting after 5 second delay");
}

비동기 작업을 반환하는 Task 객체의 반환 값을 무시한다.

작업을 할당하면 작업이 완료되려고 할 때 throw되는 예외가 표시되지 않는다.

 

private static async Task ExecuteAsyncMethods()
{
    Console.WriteLine("About to launch a task...");
    // CS4014: Because this call is not awaited, execution of the current method continues before the call is completed.
    // Consider applying the 'await' operator to the result of the call.
    Task.Run(() =>
    {
        var iterations = 0;
        for (int ctr = 0; ctr < int.MaxValue; ctr++)
            iterations++;
        Console.WriteLine("Completed looping operation...");
        throw new InvalidOperationException();
    });
    await Task.Delay(5000);
    Console.WriteLine("Exiting after 5 second delay");   
 }

반환값을 설정하지 않으면 컴파일 에러가 발생한다.

 

  • 유효한 식별자로도 사용이 가능
private static void ShowValue(int _)
{
   byte[] arr = { 0, 0, 1, 2 };
   _ = BitConverter.ToInt32(arr, 0);
   Console.WriteLine(_);
}
 // The example displays the following output:
 //       33619968

 

형식 안정성 위반으로 컴파일 에러가 발생한다.

private static bool RoundTrips(int _)
{
   string value = _.ToString();
   int newValue = 0;
   _ = Int32.TryParse(value, out newValue);
   return _ == newValue;
}
// The example displays the following compiler error:
//      error CS0029: Cannot implicitly convert type 'bool' to 'int'

 

동일한 변수명으로 선언할 수 없다. 에러 발생

public void DoSomething(int _)
{
 var _ = GetValue(); // Error: cannot declare local _ when one is already in scope
}
// The example displays the following compiler error:
// error CS0136:
//       A local or parameter named '_' cannot be declared in this scope
//       because that name is used in an enclosing local scope
//       to define a local or parameter

댓글