상세 컨텐츠

본문 제목

[C#] 람다식

.NET/C#

by 클리엘 클리엘 2021. 4. 6. 13:33

본문

728x90

람다식은 익명 메서드의 구현을 간략화하기 위해 사용됩니다.

delegate int Cal(int i, int j);

static void Main(string[] args)
{
	Cal cal = (int i, int j) => i + j;

	Console.WriteLine($"{cal(10, 20)}");
}

람다식은 => 연산자로 구분할 수 있는데 왼쪽은 매개변수, 오른쪽은 매개변수를 받아 구현되는 식이 올 수 있습니다. C#에서는 '형식 유추(Type Inference)'라고 하여 다음과 같이 더 간단하게 람다식을 구현할 수 있습니다.

Cal cal = (i, j) => i + j;

이것은 형식이 델리게이트에 의해 유추될 수 있기 때문에 가능합니다. 심지어 어떤 경우는 이 식을 이용해 식만을 가지는 클래스의 멤버를 구현하기도 합니다.

class Animal
{
	List<string> animals = new List<string>();

	public Animal() => Console.WriteLine("클래스 생성"); //생성자

	public void Add(string name) => animals.Add(name); //요소를 추가하는 메서드
	public void Remove(string name) => animals.Remove(name); //요소를 삭제하는 메서드

	public int Capacity => animals.Capacity; //읽기전용 속성
}

다른 대부분의 언어와 마찬가지로 단일식만이 오는 경우는 중괄호({})가 필요 없습니다. 바꿔 말하면 여러 문장이 필요한 경우 중갈호({})로 묶어줄 수 있음을 의미합니다.

Cal cal = (i, j) => {
	int x = 10;

	i += x;

	return i - j;
};

하지만 위와 같은 람다식구현을 위해 그에 맞는 대리자를 미리 선언해 둬야 합니다. 이 번거로움을 해결하기 위해 .NET Framework에서는 Func와 Action 대리자를 제공하고 있습니다.

 

먼저 Func의 경우 입니다. 예제에서는 int형 매개변수 2개, 그리고 반환형식이 int인 Func를 사용했습니다. Func는 반환형식이 존재하므로 전달할 매개변수가 없다면 Func<int>로만 사용할 수 있으며 매개변수가 있으면 최대 16개까지의 매개변수를 지정할 수 있습니다. 이때 반환 형식은 항상 마지막에 위치합니다.

static void Main(string[] args)
{
	Func<int, int, int> func = (i, j) => i +j;

	Console.WriteLine($"{func(10, 20)}");
}

이번에는 Action입니다. Func와는 다르게 반환형식이 존재하지 않으므로 매개변수가 없다면 Action으로 사용할 수 있으며 매개변수가 있다면 최대 16개까지의 매개변수를 지정할 수 있습니다.

static void Main(string[] args)
{
	int x = 0;

	Action<int, int> action = (i, j) => x = i + j;
	action(20, 30);

	Console.WriteLine($"{x}");
}

람다식을 Expression과 결합하면 프로그램 실행중에 필요에 따라 동적으로 메서드를 만들어 실행하는 것도 가능합니다. Expression은 식을 트리노드로 표현할 수 있도록 해주는데 이를 컴파일하여 동적으로 원하는 동작을 구현하는 것입니다.

static void Main(string[] args)
{
	Expression val = Expression.Constant(10);
	Expression opr = Expression.Parameter(typeof(int), "i");

	Expression exec = Expression.Add(val, opr);

	Expression<Func<int, int>> lambda = Expression<Func<int, int>>.Lambda<Func<int, int>>(exec, new ParameterExpression[]{ (ParameterExpression)opr });

	Func<int, int> comExec = lambda.Compile();

	Console.WriteLine(comExec(20));
}

Expression.Constant는 원래 ConstantExpression클래스의 팩토리 메서드로 ConstantExpression클래스의 객체를 생성할 수 있도록 해주며 ConstantExpression클래스는 Expression으로 상속받았으므로 Expression형식을 그대로 사용할 수 있습니다. 이와 같은 동작은 Constant뿐만 아니라 함께 사용된 Parameter팩토리 메서드 등 다른 메서드도 모두 마찬가지입니다. Expression자신은 abstract로 선언되어 있어 스스로 인스턴스를 생성할 수 없지만 팩토리 메서드를 통해서는 파생 클래스의 인스턴스를 생성해 사용하는 것입니다.

 

ConstantExpression은 상수값 자체를 나타내며 ParameterExpression은 매개변수를 나타내는 클래스입니다. 매개변수는 int형식의 i변수를 가리키고 있습니다. 기타 다른 클래스는 아래 페이지를 참고해 주세요.

 

System.Linq.Expressions 네임스페이스 | Microsoft Docs

 

System.Linq.Expressions 네임스페이스

언어 수준 코드 식을 식 트리 형식의 개체로 나타낼 수 있게 하는 클래스, 인터페이스 및 열거형이 포함되어 있습니다. Contains classes, interfaces and enumerations that enable language-level code expressions to be re

docs.microsoft.com

각각의 Expression의 클래스를 생성하고 나서는 Add메서드로 상수와 매개변수를 더할것임을 나타내고 있습니다. 이 메서드는 BinaryExpression의 인스턴스를 반환하며 BinaryExpression은 식 자체를 데이터로서 가지고 있지만 이 식 자체를 실행하려면 위 예제에서처럼 람다식으로 컴파일해야 합니다. 예제에서 사용된 Expression<T>형식이 LambdaExpression의 파생 클래스입니다.

 

참고로 람다식을 사용하면 좀 더 간단히 식 트리를 구성할 수 있습니다. 값이 정해진 경우라면 아래와 같은 방법으로도 응동이 가능합니다.

static void Main(string[] args)
{
	Expression<Func<int, int>> lambda = (i) => 10 + i;
	Func<int, int> comExec = lambda.Compile();

	Console.WriteLine(comExec(20));
}

 

728x90

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

[C#] 대리자(Delegate)  (0) 2021.04.15
[C#] 이벤트(Event)  (0) 2021.04.12
[C#] 람다식  (0) 2021.04.06
[C#] 예외처리  (0) 2021.02.25
[C#] 일반화  (0) 2021.02.11
[C#] 배열및 컬렉션과 인덱서활용 그리고 나열하기  (0) 2021.02.08

태그

관련글 더보기

댓글 영역