본문 바로가기
C#

[C#] 람다 식(=>), 입력 매개 변수와 자연 형식

by RucA 2024. 4. 29.
728x90
반응형

대리자(delegate)를 다룰 때 간단히 다룬 람다 식을 좀 더 자세히 다루려고 한다. 대리자를 통해 무명 메서드를 생성 및 호출한 것처럼, 람다 식을 사용해 익명 함수를 만들 수 있다

 

 

람다 식


람다 식은 람다 선언 연산자(=>)를 사용해 익명(Anonymous) 함수를 만든다. 람다 선언 연산자(=>)를 사용하며, 두 가지 형식으로 분류할 수 있다.

 

  • 식(expression) 람다 : => 연산자 오른쪽에 식이 있는 람다 식
  • 문(statement) 람다 : => 연산자 오른쪽에 문을 지정(중괄호 사용)하는 람다 식, 보통 여러 줄로 표현할 때 사용

문 람다의 경우 중괄호에 지정할 수 있는 문의 개수에는 제한이 없지만, 일반적으로 2-3개 정도만 지정하는 편이다.

만약 한 줄로 표현할 수 있는 람다 식의 경우는 식 람다를 사용하는 것이 코드의 간결성에 도움이 될 것이다.

 

using System;

class Lambda
{
    static Func<int, string> GetPF_State = (int score) =>
    {
        string result;

        if (score >= 75) 
            result = "Pass";
        else 
            result = "Fail";

        return result;
    };

    //식 람다는 삼항 연산자와 섞어 쓰면 편리하다.
    static string GetPF_EXPRESS(int score) => score >= 75 ? "Pass" : "Fail"; 
    
    static void Main()
    {
        Console.WriteLine(GetPF_State(80)); 
        Console.WriteLine(GetPF_EXPRESS(60)); 
    }

}
//출력 : Pass Fail

 

 

위의 예제는 문 람다와 식 람다의 차이점을 직관적으로 이해할 수 있다. 물론 문 람다도 삼항 연산자를 활용해 더 간결하게 표현할 수 있지만, 개인적인 생각으로는 문 람다는 메서드(함수)와 식 람다 사이에서 간결함과 가독성의 절충안을 선택할 때 사용하는 것이 좋다고 생각하므로, 식 람다를 두고 문 람다를 사용한다면 한 눈에 읽히도록 짜는 것이 더 중요할 것이다.

 

 

람다 식 입력 매개 변수


람다 식의 입력 매개 변수는 괄호로 묶는다. 입력 매개 변수의 개수에 따라 생략할 수 있다.

 

  • 입력 매개 변수가 0개인 경우 : 빈 괄호를 지정
//공식 문서 코드
Action line = () => Console.WriteLine();

 

  • 입력 매개 변수가 1개인 경우 : 괄호는 생략 가능
//공식 문서 코드
Func<double, double> cube = x => x * x * x;

 

  • 입력 매개 변수가 2개 이상인 경우 : 입력 매개 변수를 쉼표로 구분
//공식 문서 코드
Func<int, int, bool> testForEquality = (x, y) => x == y;

 

  • 입력 매개 변수 형식은 모두 명시적이거나 암시적 (일부 입력 매개 변수 형식만 명시하는 것이 불가능)
    • 아닌 경우 컴파일러 오류 발생
//공식 문서 코드
Func<int, string, bool> isTooLong = (int x, string s) => s.Length > x;

 

  • 무시 항목을 사용해 람다 식에서 사용하지 않는 입력 매개 변수를 두 개 이상 지정할 수 있음
    • 무시 항목 : 코드에서 의도적으로 사용을 하지 않는 자리 표시
//공식 문서 코드
Func<int, int, int> constant = (_, _) => 42;

 

  • 람다 식의 입력 매개 변수에 대한 기본값을 제공할 수 있음
    • C# 12부터 지원함
//공식 문서 코드
var IncrementBy = (int source, int increment = 1) => source + increment;

Console.WriteLine(IncrementBy(5)); // 6
Console.WriteLine(IncrementBy(5, 2)); // 7

 

  • params 배열을 입력 매개 변수로 사용할 수 있음
//공식 문서 코드
var sum = (params int[] values) =>
{
    int sum = 0;
    foreach (var value in values) 
        sum += value;
    
    return sum;
};

var empty = sum();
Console.WriteLine(empty); // 0

var sequence = new[] { 1, 2, 3, 4, 5 };
var total = sum(sequence);
Console.WriteLine(total); // 15

 

  • 입력 매개 변수 기본값 또는 params 배열을 입력 매개 변수로 사용하는 람다 식은 Func<> 또는 Action<> 형식에 해당하는 자연 형식이 없으나, 대리자 형식을 직접 정의하여(또는 var을 통한 암시적 정의) 사용할 수 있다.
//공식 문서 코드
delegate int IncrementByDelegate(int source, int increment = 1);
delegate int SumDelegate(params int[] values);

 

 

람다 식의 자연 형식


공용 형식 시스템에는 "람다 식"이라는 개념이 기본적으로는 없어 람다 식 자체에는 형식이 없다. 그러나 람다 식의 형식을 비공식적으로 언급해야 할 경우가 있는데, 이 비공식적인 형식은 대리자 형식 또는 람다 식이 변환되는 Expression 형식을 가리킨다.

 

  • C# 10부터 람다 식은 자연 형식을 가질 수 있음 : 컴파일러가 대리자 형식을 유추할 수 있음
//공식 문서 코드
var parse = (string s) => int.Parse(s);

 

위의 예제에서 컴파일러는 parse의 형식을 Func<string, int>라고 유추한다. 위와 같이 적절히 매칭이 되는 대리자가 존재할 경우 Func 또는 Action 대리자를 선택한다.

 

  • 람다 식이 자연 형식을 가진다면 System.Object 또는 System.Delegate와 같은 덜 명시적인 형식에 할당할 수 있음.
//공식 문서 코드
object parse = (string s) => int.Parse(s);   // Func<string, int>
Delegate parse = (string s) => int.Parse(s); // Func<string, int>

 

  • 자연 형식을 갖지 않는 람다 식의 경우, 사용자가 명시적으로 형식을 선언해야 함.
//공식 문서 코드
var parse = s => int.Parse(s); // ERROR: Not enough type info in the lambda
Func<string, int> parse = s => int.Parse(s); //명시적 형식 선언

 

 

 

람다식은 그 간결함 때문에 폭넓게 사용된다. 아직 다루지 않은 비동기와 LINQ 등의 개념과 함께 활용하는 유용한 방법들도 많이 있지만, 이는 이후 포스팅에서 그 개념을 다룰 때 추가적으로 덧붙여 설명하는 것으로 하겠다.

728x90
반응형