[This is C#] Chapter 14. 람다식
Table of Contents
이것이 C#이다 책을 읽고 공부한 노트입니다.
람다식 #
- 람다식(Lambda Expression)
- Chapter 13에서도 보았던 익명 메소드를 만들기 위해 사용한다.
- 림다식으로 만드는 익명 메소드는 무명 함수(Anonymouse Function) 라고 부른다.
- C# 컴파일러는 형식 유추(Type Inference)라는 기능을 제공한다. 형식 유추를 사용하면 람다식에서 매개변수의 형식을 제거할 수 있다.
delegate int Calculate(int a, int b);
class MainApp
{
static void Main(string[] args)
{
// 익명 메소드
Calculate calc1 = delegate (int a, int b)
{
return a + b;
};
// 람다식으로 만든 무명 함수 (형식 유추로 매개변수의 형식을 제거할 수 있다.)
Calculate calc2 = (a, b) => a + b;
}
}
문 형식의 람다식 #
- 문 형식의 람다 식(Statement Lambda)
a + b
같은 식이 아니라if (a == b) return 0; else return 1;
같은 문장을 사용할 수 있는 람다 식이다.=>
연산자의 오른편이{ }
과 같은 코드 블록을 만든다.
delegate void DoSomething();
class MainApp
{
static void Main(string[] args)
{
// 문 형식의 람다 식
DoSomething doIt = () =>
{
Console.WriteLine("뭔가를");
Console.WriteLine("출력해");
Console.WriteLine("보자!");
};
doIt();
}
}
Func와 Action으로 더 간편하게 무명 함수 만들기 #
- .NET 안에 미리 선언되어 있는 대리자들이다.
Func 대리자 #
Func
대리자- 결과를 반환하는 메소드를 참조하기 위해 만들어졌다.
static void Main(string[] args)
{
Func<int> func1 = () => 1;
Func<int, int> func2 = (a) => a + 1;
Func<int, int, int> func3 = (a, b) => a + b + 1;
}
Action 대리자 #
Action
대리자- 반환 형식이 없는 메소드를 참조하기 위해 만들어졌다.
static void Main(string[] args)
{
Action action1 = () => Console.WriteLine("Hello");
int result = 0;
Action<int> action2 = (a) => result = a;
Action<int, int> action3 = (a, b) => result = a + b;
}
식 트리 #
- 식 트리(Expression Tree)
- 식을 트리 구조로 표현한 것이다.
- C#은 프로그래머가 코드로 직접 식 트리를 조립하고 컴파일해서 사용할 수 있다.
- 식 드리를 다루는 데 필요한 클래스들은
System.Linq.Expressions
네임스페이스 안에 준비되어 있다.- 모두
Expression
클래스의 파생 클래스들이다. Expression
클래스 자신은abstract
클래스여서 자신의 인스턴스를 만들 수는 없지만, 파생 클래스의 인스턴스를 생성하는 정적 팩토리 메소드를 제공한다.
- 모두
Expression const1 = Expression.Constant(1);
Expression const2 = Expression.Constant(2);
Expression leftExp = Expression.Multiply(const1, const2); // 1 * 2
Expression param1 = Expression.Parameter(typeof(int)); // x
Expression param2 = Expression.Parameter(typeof(int)); // y
Expression righExp = Expression.Subtract(param1, param2); // x - y
Expression exp = Expression.Add(leftExp, righExp); // (1 * 2) + (x - y) // body
Expression<Func<int, int, int>> expression = Expression<Func<int, int, int>>.Lambda<Func<int, int, int>>(
exp, new ParameterExpression[] {(ParameterExpression) param1, (ParameterExpression) param2}
);
Func<int, int, int> func = expression.Compile();
Console.WriteLine($"{func(7, 8)}"); // 1
- 람다 식을 이용하면 더 간편하게 식 트리를 만들 수 있다.
- 다만 이 경우에는 동적으로 식 트리를 만들기는 어려워진다.
Expression<Func<int, int, int>> expression = (a, b) => (1 * 2) + (a - b);
Func<int, int, int> func = expression.Compile();
Console.WriteLine($"{func(7, 8)}"); // 1
식으로 이루어지는 멤버 #
- 클래스의 멤버 중에서 본문이 중괄호로 만들어져 있는 것들
- 메소드, 생성자, 종료자, 프로퍼티, 인덱서
- 이것은 모두 본문을 식으로만 구현할 수 있다. 이것을 식 본문 멤버(Expression-Bodied Member) 라고 한다.
class MyList
{
private List<int> list = new List<int>();
// 읽기 전용 프로퍼티와 인덱서
public int Capacity => list.Capacity;
public int this[int idx] => list[idx];
// 읽기, 쓰기 모두 가능한 프로퍼티와 인덱서
public int Capacity
{
get => list.Capacity;
set => list.Capacity = value;
}
public int this[int idx]
{
get => list[idx];
set => list[idx] = value;
}
// 생성자와 소멸자
public MyList() => Console.WriteLine("Hello");
~MyList() => Console.WriteLine("Bye");
// 메서드들
public void Add(int val) => list.Add(val);
public void Remove(int val) => list.Remove(val);
}