[C#] Lambda Expression(람다 식) 이란?

2021. 7. 12. 15:56·etc/C#

C#을 비롯한 여러 언어들에서 람다 식을 지원하는데

 

이 람다 식이란 과연 무엇일까?

 

람다식의 기본 원형은 다음 두가지가 있을 수 있다.

 

(parameter) => expression
(parameter) => { statements };

이렇게만 봐서는 전혀 모르겠으니 아래를 보자

 

 

 

람다 식은 도대체 뭘까?

람다 식을 보다 정확하게 이해하려면 우선 delegate(대리자)에 대해 알아야 한다.

 

delegate에 대해 설명하는 글은 여기에 있다.

// 링크

 

글을 읽었다 가정하고, delegate를 이용해 익명 메소드를 전달하는 방식 중 제일 단점은

 

매번 delegate라는 키워드로 함수를 감싸줘야 한다는것이다.

 

이 불편함을 해소하고자 Lamda Expression이 나오게 되었다.

 

람다식은 익명메소드의 완벽한 상위호환 버전이다.

 

따라서 람다식만 알아도 충분한데, 왜 익명메소드에 대해 설명하는 글이나 정보들이 있을까?

 

그 이유는 익명메소드가 나온 다음에 람다식이 나오게 되었는데 MS에서 기존 코드와의 호환성을 위해

 

굳이 익명메소드를 삭제하지 않고 람다식을 추가했기 때문이다.

 

아무튼 이 불편함을 없애고자 나온게 Lamda Expression이다.

 

 

 

간단한 익명메소드 사용예시를 보면 다음과 같다.

 

class Test
{
	delegate int Chain(int a, int b);

	static void Main()
    {
    	Chain chain = delegate(int a, int b)
        {
        	return a+b;
        }
        Console.WriteLine(chain(3,4)); // 7출력
    }
}

파라미터로 int a, int b를 받고 이 둘을 더한값을 리턴하는 함수를 delegate에 등록해주고 delegate 인스턴스를 이용해

 

마치 함수를 호출하듯이 사용했다.

 

람다식을 사용하면 어떻게 될까?

 

 

 

class Test
{
	delegate int Chain(int a, int b);

	static void Main()
    {
    	Chain chain = (int a, int b) =>
        {
        	return a+b;
        }
        Console.WriteLine(chain(3,4)); // 7출력
    }
}​

delegate 키워드가 사라지고 => 라는 코드가 추가되었다.

 

여기서 조금 더 나아가 parameter의 자료형이 생략 가능하다.

 

class Test
{
	delegate int Chain(int a, int b);

	static void Main()
    {
    	Chain chain = (a, b) =>
        {
        	return a+b;
        }
        Console.WriteLine(chain(3,4)); // 7출력
    }
}​

이게 될 수 있는 이유는 delegate에 등록할 때 등록할 delegate의 parameter들을 보고 자료형을 유추 할 수 있기 때문이다.

 

끝이 아니다, return a+b 는 비교적 간단하여 이를 brace로 묶지 않고 생략할 수 있다. 

 

또 기본적으로 값을 반환하다고 가정하여 return문을 생략할 수 있다.

 

class Test
{
	delegate int Chain(int a, int b);

	static void Main()
    {
    	Chain chain = (a, b) => { return a+b };
    	Chain chain = (a, b) => a+b;
        // 위의 람다 식 두가지 표현은 완전 동일하다
        Console.WriteLine(chain(3,4)); // 7출력
    }
}​

 

여기까지 봤을 때, 기존 익명메소드의 귀찮은점을 많이 해결한것 같지만

 

하나 남은게 있는데 그것은 delegate 선언이다. 

 

하지만 이것도 없앨 수 있는데 

 

System 네임스페이스에는 MS가 미리 선언해놓은 delegate인 Action과 Func가 다음과 같이 선언되어 있다.

 

최대 16개까지의 parameter를 전달할 수 있게 override 되어있다.

public delegate void Action();
public delegate void Action<in T>(T arg);
public delegate void Action<in T1,in T2>(T1 arg1, T2 arg2);
....

public delegate TResult Func<out TResult>();
public delegate TResult Func<in T1, out TResult>();
public delegate TResult Func<in T1, in T2, out TResult>();
...

편리해지기 위해 사용하는 람다 식인데 오히려 delegate를 선언해야 하는 그러한 모순을

 

Action과 Func로 타파할 수 있다.

 

Action delegate

delegate의 원형을 보면 알겠지만 반환형이 void이다.

 

즉 결과를 반환하는 함수가 아닌 그저 실행이 목적이 함수이다.

 

제네릭 안에 들어가 있는건 파라미터의 type이다.

 

사용 예시를 보자

 

using System;

class Test
{
	static void Main()
    {
    	Action myAction = () => Console.WriteLine("Hello");
        Action<int> myAction2 = (x) => Console.WriteLine($"input number is {x}");
        Action<int, int> myAction3 = (a,b) => Console.WriteLine($"{a} * {b} = {a*b}");
        
        myAction(); // Hello
        myAction2(4); // input number is 4
        myAction3(3,4); // 3*4 = 12
    }
}​

 

상당히 직관적이라 이해가 쉽다.

 

Func delegate

Action과 반대로 Func는 반환형이 존재하게 된다.

 

결과를 반드시 내놓아야 한다는 뜻이다.

 

delegate의 반환형은 제네릭의 맨 오른쪽 끝인 TResult가 정의해준다.

 

사용 예시를 보자

 

using System;

class Test
{
	static void Main()
    {
    	Func<int> myFunc = () => 10;
        Func<int, int> myFunc2 = (x) => x*x;
        Func<int, int, int> myFunc3 = (a, b) => a + b;
        
        Console.WriteLine(myFunc()); // 10
        Console.WriteLine(myFunc2(4)); // 16
        Console.WriteLine(myFunc3(3,4)); // 7
    }
}​

 

 

마지막으로 함수 자체에 람다 식을 대입할 수 있다.

 

using System;

class Test
{
	int number;
	static void Main()
    {
    	Print("Hello");
        Console.WriteLine(GetNumber());
    }
    
    static void Print(string s) => Console.WriteLine(s);
    
    static int GetNumber() => number;
}​

 

 

람다 식은 왜 쓰는걸까?

익명메소드의 사용이유와 같은데, 그래도 써보자면

 

1.한번만 사용될 함수를 굳이 정의하지 않기 위해서

  • 코드의 간결성을 높여준다

2.파라미터에 함수 그대로를 넘기고 싶어서

  • C++의 함수 포인터처럼 함수를 파라미터화 시킬 수 있다.

 

 

 

 

저작자표시 (새창열림)

'etc > C#' 카테고리의 다른 글

[C#] Lambda Function Capture  (1) 2021.07.30
[C#] switch 제어문  (0) 2021.07.16
[C#] 문자열 보간(Interpolation)  (0) 2021.07.15
[C#] Property(프로퍼티), C#만의 특별한 기능  (0) 2021.07.13
[C#] Null-Safety를 지원하는 C#  (0) 2021.07.13
'etc/C#' 카테고리의 다른 글
  • [C#] switch 제어문
  • [C#] 문자열 보간(Interpolation)
  • [C#] Property(프로퍼티), C#만의 특별한 기능
  • [C#] Null-Safety를 지원하는 C#
imsongkk
imsongkk
이것저것 적어보는 개발 블로그
  • imsongkk
    이것저것
    imsongkk
  • 전체
    오늘
    어제
    • 분류 전체보기 (81)
      • 일상 (1)
      • Infra (21)
        • AWS (3)
        • Docker (8)
        • Kubernetes (9)
        • Terraform (1)
      • Trouble Shooting (9)
      • Back-End (18)
        • Spring Boot (2)
        • JPA (7)
        • HTTP 기본 (4)
        • DDD (3)
      • 소마 (4)
      • Programming (7)
        • 디자인 패턴 (7)
      • etc (19)
        • Unity (4)
        • Node.js (2)
        • React (1)
        • 리액트를 다루는 기술 (2)
        • C# (6)
        • Language (0)
        • Firebase (2)
        • 알고리즘 (1)
        • CS (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 글쓰기
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    소프트웨어 마에스트로 #소마 #SWM #소프트웨어 마에스트로 14기
    Firebase
    EC2
    8080
    Push
    Google Analytics
    Terraform #테라폼 #IaC #AWS CLI
    Private
    firestore
    React
    Firebase Analytics
    Repository
    VPC #Subnet #NAT #Region #AZ #IGW
    Pull
    clone
    Git
    3000
    도메인
    포트
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
imsongkk
[C#] Lambda Expression(람다 식) 이란?
상단으로

티스토리툴바