포슀트

πŸŒ’ C# Lambda-Expression | λžŒλ‹€μ‹

πŸ’« Q


  • λžŒλ‹€μ‹ ?
  • λžŒλ‹€μ‹μ„ μ„ μ–Έν•˜κ³  μ‚¬μš©ν•˜λŠ” 방법
  • λ¬Έ ν˜•μ‹μ˜ λžŒλ‹€μ‹μ„ μž‘μ„±ν•˜κ³  μ‚¬μš©ν•˜λŠ” 방법
  • 식 트리

πŸ’« Lambda-Expression | λžŒλ‹€μ‹


읡λͺ…-λ©”μ†Œλ“œλ₯Ό λ§Œλ“œλŠ” 또 ν•˜λ‚˜μ˜ 방법.
λžŒλ‹€μ‹μœΌλ‘œ λ§Œλ“œλŠ” 읡λͺ… λ©”μ†Œλ“œλŠ” 무λͺ…-ν•¨μˆ˜(Anonymous Function)λΌλŠ” μ΄λ¦„μœΌλ‘œ λΆ€λ₯Έλ‹€.

🫧 Lambda-Expression κ΅¬ν˜„

(λ§€κ°œλ³€μˆ˜) => 식 같은 λͺ¨μ–‘μœΌλ‘œ λ§Œλ“ λ‹€.

=> λŠ” μž…λ ₯ μ—°μ‚°μž (ν˜Ήμ€ λžŒλ‹€ μ—°μ‚°μž(Lambda Operator)).
=>λ₯Ό μ€‘μ‹¬μœΌλ‘œ μ™Όμͺ½μ—λŠ” λ§€κ°œλ³€μˆ˜, 였λ₯Έμͺ½μ—λŠ” 식이 μœ„μΉ˜.
κ·Έμ € μ™Όμͺ½ 맀개 λ³€μˆ˜λ₯Ό 였λ₯Έμͺ½ 식에 μ „λ‹¬ν•˜λŠ” μ—­ν• .

1
(int x, int y) => x + y

🫧 Type-Inference | νƒ€μž… μΆ”λ‘ (ν˜•μ‹ μœ μΆ”)

C# μ»΄νŒŒμΌλŸ¬λŠ” μ½”λ“œλ₯Ό ν•œμΈ΅ 더 κ°„κ²°ν•˜κ²Œ λ§Œλ“€ 수 μžˆλ„λ‘ νƒ€μž… μΆ”λ‘ (ν˜•μ‹ μœ μΆ”) (Type-Inference)λ₯Ό μ§€μ›ν•œλ‹€.
νƒ€μž… 좔둠을 μ΄μš©ν•˜λ©΄ λžŒλ‹€μ‹μ—μ„œ 맀개 λ³€μˆ˜μ˜ νƒ€μž…μ„ μ œκ±°ν•  수 μžˆλ‹€.

1
2
3
4
delegate int MyDelegate(int x, int y);

// C# μ»΄νŒŒμΌλŸ¬κ°€ `delegate`의 μ„ μ–Έ μ½”λ“œλ‘œλΆ€ν„° 무λͺ… ν•¨μˆ˜μ˜ 맀개 λ³€μˆ˜ νƒ€μž…μ„ μΆ”λ‘ ν•΄λ‚Έλ‹€.
MyDelegate myDelegate = (x, y) => x + y;

🫧 Lambda-Expression Why?

λžŒλ‹€μ‹μœΌλ‘œ λ§Œλ“œλŠ” 무λͺ…ν•¨μˆ˜λŠ”, λŒ€λ¦¬μžλ₯Ό μ΄μš©ν•œ 읡λͺ… λ©”μ†Œλ“œλ³΄λ‹€ κ°„κ²°ν•˜λ‹€.

더 번거둜운 방법과 더 κ°„κ²°ν•œ 방법이 λ™μ‹œμ— μ‘΄μž¬ν•˜λŠ” 이유 ?
λŒ€λ¦¬μžλ₯Ό μ΄μš©ν•œ 읡λͺ… λ©”μ†Œλ“œλŠ” C# 2.0μ—μ„œ λ„μž…, λžŒλ‹€μ‹μ€ C# 3.0μ—μ„œ λ„μž….
ν•˜μœ„ ν˜Έν™˜μ„±μ„ μœ μ§€ν•˜κΈ° μœ„ν•΄ 두 가지 방법을 λͺ¨λ‘ 지원.

1
2
3
4
5
6
7
delegate int MyDelegate(int x, int y);

// 읡λͺ…-λ©”μ†Œλ“œ
MyDelegate myDelegate = delegate (int x, int y) { return x + y; };

// λžŒλ‹€μ‹
MyDelegate myDelegate = (x, y) => x + y;

🫧 Statement Lambda | λ¬Έ ν˜•μ‹μ˜ λžŒλ‹€μ‹

식 ν˜•μ‹μ˜ λžŒλ‹€μ‹λŠ” => μ—°μ‚°μžμ˜ 였λ₯ΈνŽΈμ— 식을 μ‚¬μš©.
λ¬Έ ν˜•μ‹μ˜ λžŒλ‹€μ‹μ€ => μ—°μ‚°μžμ˜ 였λ₯ΈνŽΈμ— μ€‘κ΄„ν˜Έ({})λ₯Ό μ‚¬μš©ν•˜μ—¬ μ½”λ“œ 블둝을 μž‘μ„±.

μ—¬λŸ¬ μ€„μ˜ μ½”λ“œλ₯Ό μ‚¬μš©ν•  수 있으며, return ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ°˜ν™˜κ°’μ„ 지정할 수 μžˆλ‹€.
λ°˜ν™˜ ν˜•μ‹μ΄ μ—†λŠ” 무λͺ…-ν•¨μˆ˜λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
(int x, int y) => { /* ... */ }
(int x, int y) =>
{
	// ...
	return x + y;
}

( ) => { /* ... */ }
( ) =>
{
	// ...
	return 0;
}

πŸ’« Expression-Tree | 식-트리


식을 트리둜 ν‘œν˜„ν•œ 자료 ꡬ쑰.

예λ₯Ό λ“€μ–΄ 1 * 2 + (7 - 8) 같은 식을 트리둜 ν‘œν˜„ν•˜λ©΄ μ•„λž˜κ³Ό κ°™λ‹€.

1
2
3
4
5
   +
  / \
 *   -
/ \ / \
1 2 7 8

식 νŠΈλ¦¬μ—μ„œ μ—°μ‚°μžλŠ” λΆ€λͺ¨ λ…Έλ“œκ°€ 되며, ν”Όμ—°μ‚°μžλŠ” μžμ‹ λ…Έλ“œκ°€ λœλ‹€.
μ΄λ ‡κ²Œ 식 트리둜 ν‘œν˜„λœ 식은 트리의 잎 λ…Έλ“œλΌλ¦¬ κ³„μ‚°ν•΄μ„œ μ°¨λ‘€μ°¨λ‘€ λ£¨νŠΈκΉŒμ§€ μ˜¬λΌκ°€λ©΄ 전체 μ‹μ˜ κ²°κ³Όλ₯Ό 얻을 수 μžˆλ‹€.

🫧 Expression-Tree Why?

μ™„μ „ν•œ C# μ»΄νŒŒμΌλŸ¬λŠ” μ•„λ‹ˆμ§€λ§Œ,
ν”„λ‘œκ·Έλž˜λ¨Έκ°€ μ½”λ“œ μ•ˆμ—μ„œ 직접 식 트리λ₯Ό μ‘°λ¦½ν•˜κ³  μ»΄νŒŒμΌν•΄μ„œ μ‚¬μš©ν•  수 μžˆλŠ” κΈ°λŠ₯을 제곡.
λ‹€μ‹œ 말해, ν”„λ‘œκ·Έλž¨ μ‹€ν–‰ 쀑에 λ™μ μœΌλ‘œ 무λͺ… ν•¨μˆ˜λ₯Ό λ§Œλ“€μ–΄ μ‚¬μš©ν•  수 있게 ν•΄μ€€λ‹€λŠ” 이야기.

식 트리 자료 κ΅¬μ‘°λŠ” μ»΄νŒŒμΌλŸ¬λ‚˜ 인터프리터λ₯Ό μ œμž‘ν•˜λŠ” 데도 μ‘μš©.
μ»΄νŒŒμΌλŸ¬λŠ” ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄μ˜ 문법을 따라 μž‘μ„±λœ μ†ŒμŠ€ μ½”λ“œλ₯Ό λΆ„μ„ν•΄μ„œ 식 트리둜 λ§Œλ“  ν›„, 이λ₯Ό λ°”νƒ•μœΌλ‘œ μ‹€ν–‰ νŒŒμΌμ„ λ§Œλ“ λ‹€.

πŸ’« Expression


🫧 Expression Class

Expression ν΄λž˜μŠ€μ™€ 아이듀(νŒŒμƒ ν΄λž˜μŠ€λ“€).
식 트리λ₯Ό λ‹€λ£¨λŠ”λ° ν•„μš”ν•œ 클래슀.

System.Linq.Expressionsλ„€μž„μŠ€νŽ˜μ΄μŠ€μ— μ •μ˜λ˜μ–΄ μžˆλ‹€.

Expression ν΄λž˜μŠ€λŠ” 식 트리λ₯Ό κ΅¬μ„±ν•˜λŠ” λ…Έλ“œλ₯Ό ν‘œν˜„
κ·Έλž˜μ„œ Expression을 μƒμ†λ°›λŠ” νŒŒμƒ ν΄λž˜μŠ€λ“€ μ—­μ‹œ 식 트리의 각 λ…Έλ“œλ₯Ό ν‘œν˜„

Expression ν΄λž˜μŠ€λŠ” νŒŒμƒ ν΄λž˜μŠ€λ“€μ˜ 객체λ₯Ό μƒμ„±ν•˜λŠ” 역할도 λ‹΄λ‹Ή
νŒŒμƒ 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λŠ” 정적 νŒ©ν† λ¦¬ λ©”μ†Œλ“œλ₯Ό 제곡.

Expression 클래슀 μžμ²΄λŠ” 좔상 ν΄λž˜μŠ€μ΄λ―€λ‘œ 직접 μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 μˆ˜λŠ” μ—†λ‹€.

🫧 Expression κ΅¬ν˜„

Expressin 클래슀의 정적 νŒ©ν† λ¦¬ λ©”μ†Œλ“œλ₯Ό ν†΅ν•œ 객체 생성.

ν”„λ‘œκ·Έλž˜λ¨ΈλŠ” 각 λ…Έλ“œκ°€ μ–΄λ–€ νƒ€μž…μΈμ§€ μ‹ κ²½ 쓰지 μ•Šκ³  거침없이 Expression ν˜•μ‹μ˜ μ°Έμ‘°λ₯Ό μ„ μ–Έν•΄μ„œ μ‚¬μš©ν•  수 μžˆλ‹€.
ν•„μš”ν•œ κ²½μš°μ—λŠ” 각 μ„ΈλΆ€ ν˜•μ‹μœΌλ‘œ ν˜•λ³€ν™˜μ„ ν•˜λ©΄ λ˜λ‹ˆκΉŒ.
이것이 νŒ©ν† λ¦¬ λ©”μ†Œλ“œ νŒ¨ν„΄μ˜ 맀λ ₯.

1
2
3
4
5
Expression const1 = Expression.Constant(1);// μƒμˆ˜ ν‘œν˜„μ‹ 객체 생성
Expression param1 = Expression.Parameter(typeof(int), "x"); // λ§€κ°œλ³€μˆ˜ ν‘œν˜„μ‹ 객체 생성

Expression exp = Expression.Add(const1, param1); // λ§μ…ˆ ν‘œν˜„μ‹ 객체 생성
// '1 + x' λ₯Ό λ‚˜νƒ€λ‚΄λŠ” 식 트리

🫧 Expression 컴파일/μ‹€ν–‰

식 νŠΈλ¦¬λŠ” κ²°κ΅­ β€œμ‹β€μ„ 트리둜 ν‘œν˜„ν•œ 것에 뢈과.
λ‹€μ‹œ 말해, μ‹€ν–‰ κ°€λŠ₯ν•œ μƒνƒœκ°€ μ•„λ‹ˆλΌ κ·Έμ € β€œλ°μ΄ν„°β€ μƒνƒœμ— 머물러 μžˆλ‹€λŠ” 말.

μžμ‹ μ˜ 트리 자료 ꡬ쑰 μ•ˆμ— μ •μ˜λ˜μ–΄ μžˆλŠ” 식을 μ‹€ν–‰ν•  수 있으렀면 λžŒλ‹€μ‹μœΌλ‘œ μ»΄νŒŒμΌλ˜μ–΄μ•Ό ν•œλ‹€.

λžŒλ‹€μ‹μœΌλ‘œμ˜ μ»΄νŒŒμΌμ€ Expression<TDelegate> 클래슀λ₯Ό μ΄μš©ν•œλ‹€.
(Expression <- LambdaExpression <- Expression<TDelegate>)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Expression const1 = Expression.Constant(1);
Expression param1 = Expression.Parameter(typeof(int), "x");

Expression exp = Expression.Add(const1, param1);

// λžŒλ‹€μ‹ LambdaExpression (μ •ν™•νžˆλŠ” νŒŒμƒ 클래슀인 Expression<TDelegate>) 생성
Expression<Func<int, int>> lambda1 = 
	Expression.Lambda<Func<int, int>>( // λ°˜ν™˜κ°’μ΄ int이고 λ§€κ°œλ³€μˆ˜κ°€ int인 λžŒλ‹€μ‹μ„ λ§Œλ“­λ‹ˆλ‹€.
		exp,
		new ParameterExpression[] { (ParameterExpression)param1 });

// μ‹€ν–‰κ°€λŠ₯ν•œ μ½”λ“œλ‘œ 컴파일
Func<int, int> compiledExp = lambda1.Compile();

// 컴파일된 λžŒλ‹€μ‹μ„ μ‹€ν–‰
Console.WriteLine(compiledExp(3)); // Output : 4

🫧 Expression λžŒλ‹€μ‹ ν™œμš©

λžŒλ‹€μ‹μ„ μ΄μš©ν•˜λ©΄ 더 κ°„λ‹¨ν•˜κ²Œ 식 트리λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.

λ‹€λ§Œ 이 κ²½μš°μ—λŠ” β€œλ™μ μœΌλ‘œβ€ 식 트리λ₯Ό λ§Œλ“€κΈ°λŠ” μ–΄λ €μ›Œμ§„λ‹€.
Expression ν˜•μ‹μ€ β€œλΆˆλ³€ (Immutable)”이기 λ•Œλ¬Έμ—, ν•œ 번 μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€λ©΄ μˆ˜μ •ν•  수 μ—†λ‹€.

1
2
3
4
Expression<Func<int, int>> lambda2 = (x) => 1 + x;
Func<int, int> compiledExp = lambda2.Compile();

Console.WriteLine(compiledExp(3)); // Output : 4

🫧 Expression So?

식 νŠΈλ¦¬λŠ” μ½”λ“œλ₯Ό β€œλ°μ΄ν„°β€λ‘œμ¨ 보관할 수 μžˆλ‹€.
νŒŒμΌμ— μ €μž₯ν•  μˆ˜λ„ 있고 λ„€νŠΈμ›Œν¬λ₯Ό 톡해 λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€μ— 전달할 μˆ˜λ„ μžˆλ‹€.

심지어 μ½”λ“œλ₯Ό λ‹΄κ³  μžˆλŠ” 식 트리 데이터λ₯Ό 데이터 베이슀 μ„œλ²„μ— λ³΄λ‚΄μ„œ μ‹€ν–‰μ‹œν‚¬ μˆ˜λ„ μžˆλ‹€.

데이터 베이슀 처리λ₯Ό μœ„ν•œ 식 νŠΈλ¦¬λŠ” LINQμ—μ„œ μ‚¬μš©λœλ‹€
LINQλ₯Ό μ΄ν•΄ν•˜λ €λ©΄ λžŒλ‹€μ‹κ³Ό 식 트리λ₯Ό μ΄ν•΄ν•˜κ³  μžˆμ–΄μ•Όν•œλ‹€.

🫧 Expression-Bodied Member | 식 λ³Έλ¬Έ 멀버

β€˜λ©”μ†Œλ“œ, 속성(μΈλ±μ„œ), μƒμ„±μž, μ’…λ£Œμžβ€™μ˜ κ³΅ν†΅λœ νŠΉμ§•?
λͺ¨λ‘ 클래슀의 λ©€λ²„λ‘œμ„œ 본문이 μ€‘κ΄„ν˜Έλ‘œ λ§Œλ“€μ–΄μ Έ μžˆλ‹€.

μ΄λŸ¬ν•œ λ©€λ²„μ˜ 본문을 식(Expression)만으둜 κ΅¬ν˜„ν•˜λŠ” 것이 κ°€λŠ₯ν•˜λ‹€.
멀버 => 식 ν˜•νƒœλ‘œ κ΅¬ν˜„ν•œλ‹€.

μ΄λ ‡κ²Œ μ‹μœΌλ‘œ κ΅¬ν˜„λœ 멀버λ₯Ό 식 λ³Έλ¬Έ 멀버(Expression-Bodied Member)라고 λΆ€λ₯Έλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class MyClass
{
	private List<int> list = new List<int>();

	// λ©”μ†Œλ“œ
	public void Add(int value) => list.Add(value);

	// 읽기 μ „μš© 속성
	public int Capacity => list.Capacity;

	// 읽기 / μ“°κΈ° κ°€λŠ₯ν•œ 속성, μΈλ±μ„œ [1]
	public int this[int index]
	{
		get => list[index];
		set => list[index] = value;
	}

	// μΈλ±μ„œ [2]
	public int this[int index] => list[index];

	// μƒμ„±μž, μ’…λ£Œμž
	public MyClass(int value) => this.value = value;
	~MyClass() => Console.WriteLine("μ†Œλ©Έμž 호좜");
}

πŸ’« λ©”λͺ¨/μ°Έκ³ 


  • Ξ»-Expression
  • Ξ»λŠ” 그리슀 λ¬Έμžμ—μ„œ L에 ν•΄λ‹Ήν•˜λŠ” 문자
    • μ•Œλ‘ μ‘° μ²˜μΉ˜λŠ” 이 문자λ₯Ό ν•¨μˆ˜ ν‘œκΈ°λ₯Ό μœ„ν•œ 기호둜 ^λ₯Ό μ‚¬μš©ν–ˆλŠ”λ°, μ΄λŠ” ν”„λ¦°ν„°μ—μ„œ 어렀움이 μžˆμ–΄ λ둜 λ°”κΏ¨λ‹€κ³  함
  • => λ₯Ό ν™”μ‚΄ν‘œ μ—°μ‚°μžλΌκ³ λ„ λΆ€λ₯Έλ‹€.
    • 이 경우, => λ₯Ό μ΄μš©ν•œ 식을 ν™”μ‚΄ν‘œ ν•¨μˆ˜λΌκ³  λΆ€λ₯Έλ‹€.
  • β€˜μ΄κ²ƒμ΄ C#이닀.’, β€˜MSDN’
  • TODO: C# λžŒλ‹€ ν΄λ‘œμ € 원리

  • TODO: LINQ
  • TODO: νŒ©ν† λ¦¬ νŒ¨ν„΄ (νŒ©ν† λ¦¬ λ©”μ†Œλ“œ)
  • TODO: ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄λ‘ κ³Ό 연관지어 (μ‹νŠΈλ¦¬)

🫧 Lambda-Expression 배경

μ•Œλ‘ μ‘° 처치(Alonzo Church)
1936년에 κ³ μ•ˆν•œ λžŒλ‹€ 계산법(Lambda Calculus : λžŒλ‹€ λŒ€μˆ˜)μ—μ„œ 유래.

  • λžŒλ‹€ 계산법 :
    • μˆ˜ν•™ κΈ°μ΄ˆλ‘ μ„ μ—°κ΅¬ν•˜λ˜ 쀑, λΆ„λͺ…ν•˜κ³  κ°„κ²°ν•œ λ°©λ²•μœΌλ‘œ ν•¨μˆ˜λ₯Ό λ¬˜μ‚¬ν•˜κΈ° μœ„ν•΄ κ³ μ•ˆ
    • 크게 ν•¨μˆ˜μ˜ μ •μ˜μ™€ λ³€μˆ˜, 그리고 ν•¨μˆ˜μ˜ 적용으둜 ꡬ성
    • 이 κ³„μ‚°λ²•μ—μ„œλŠ” λͺ¨λ“  것이 ν•¨μˆ˜λ‘œ 이루어져 있음, 심지어 β€˜0, 1, 2 …’ 같은 μˆ«μžλ„ ν•¨μˆ˜λ‘œ ν‘œν˜„
    • λ”°λΌμ„œ λžŒλ‹€ κ³„μ‚°λ²•μ—μ„œλŠ” μ–΄λ–€ 값을 λ³€μˆ˜μ— λŒ€μž…ν•˜κ³  μ‹ΆμœΌλ©΄ ν•¨μˆ˜λ₯Ό λ³€μˆ˜μ— λŒ€μž…ν•˜λ©°, 이것을 ν•¨μˆ˜μ˜ 적용이라고 뢀름

μ œμžμ˜€λ˜ μ‘΄ λ§€μΉ΄μ‹œ(John McCarthy).
이것을 λ‹¨μˆœνžˆ μˆ˜ν•™ 이둠에 κ·ΈμΉ˜μ§€ μ•Šκ³ , ν”„λ‘œκ·Έλž˜λ° 언어에 λ„μž…ν•  수 μžˆκ² λ‹€λŠ” 아이디어λ₯Ό μ œμ‹œ.
50λ…„λŒ€ 말에 LISPλΌλŠ” μ–Έμ–΄λ₯Ό 개발.

이후 λžŒλ‹€ κ³„μ‚°λ²•μ˜ κ°œλ…μ€ 이후 λ‹€λ₯Έ ν”„λ‘œκ·Έλž˜λ° 언어에도 λ„μž…λ˜μ—ˆμœΌλ©°,
C#, C++, Java, Python 같은 μ£Όλ₯˜ ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄λŠ” λŒ€λΆ€λΆ„ λžŒλ‹€μ‹μ„ 지원.

이 κΈ°μ‚¬λŠ” μ €μž‘κΆŒμžμ˜ CC BY 4.0 λΌμ΄μ„ΌμŠ€λ₯Ό λ”°λ¦…λ‹ˆλ‹€.