---
title: "람다는 이름 없이 그 자리에서 만드는 메서드다"
description: "한 번 쓰고 말 동작에 이름을 붙이지 않습니다. 넘기는 자리에 바로 적습니다."
author: "유니얼"
pubDate: 2026-09-09
category: "programming/csharp/basics"
tags: ["C#", "기초"]
canonical: https://blog.unialgames.com/posts/csharp-lambda/
---
앞 글에서 조건을 넘겼습니다.

```csharp
bool IsEven(int n) { return n % 2 == 0; }

Count(nums, IsEven);
```

`IsEven` 은 이 한 줄에서만 씁니다. 그런데 이름을 짓고 클래스 어딘가에 메서드로 만들어야 했습니다.
조건이 열 개면 메서드가 열 개 생기고, 각각 어디 있는지 찾아다녀야 합니다.

> **한 번 쓰고 말 동작이면 이름을 붙이지 않고 그 자리에 적으면 됩니다.**

## 람다는 이렇게 생겼다

```csharp
Count(nums, n => n % 2 == 0);
```

`n => n % 2 == 0` 이 람다입니다. 세 부분입니다.

<figure class="diagram">
<svg viewBox="0 0 680 150" role="img" aria-label="람다식의 세 부분. 매개변수, 화살표, 본문">
<g font-family="var(--font-mono)" font-size="18">
<text x="60" y="50" fill="var(--text)">n</text>
<text x="96" y="50" fill="var(--accent)">=&gt;</text>
<text x="146" y="50" fill="var(--text)">n % 2 == 0</text>
</g>
<g stroke="var(--border)" stroke-width="1.4" fill="none">
<path d="M66 62 L66 90 L200 90"></path>
<path d="M110 62 L110 108 L200 108"></path>
<path d="M210 62 L210 126 L280 126"></path>
</g>
<g font-size="13" fill="var(--text-muted)">
<text x="212" y="94">받을 것. 타입은 안 적어도 된다</text>
<text x="212" y="112">이 앞을 받아서 이 뒤를 한다</text>
<text x="292" y="130">할 일. 결과가 그대로 돌아간다</text>
</g>
</svg>
<figcaption>매개변수, 화살표, 본문. 이름도 반환 타입도 없다.</figcaption>
</figure>

메서드와 비교하면 지운 것이 많습니다.

```csharp
bool IsEven(int n) { return n % 2 == 0; }
        n => n % 2 == 0
```

- **이름이 없습니다.** 그 자리에서 쓰고 버리니 부를 일이 없습니다.
- **반환 타입이 없습니다.** 본문을 보면 `bool` 인 것이 뻔합니다.
- **매개변수 타입이 없습니다.** `Func<int, bool>` 자리에 넣었으니 `int` 인 것도 뻔합니다.
- **`return` 과 중괄호가 없습니다.** 한 줄이면 그 결과가 그대로 돌아갑니다.

컴파일러가 알아낼 수 있는 것을 전부 지운 것입니다. 새 문법이 아니라 **짧게 적는 방법**입니다.

## 모양 몇 가지

```csharp
n => n * 2                    // 하나 받기
(a, b) => a + b               // 둘 이상은 괄호로 묶습니다
() => Console.WriteLine("안녕")  // 안 받으면 빈 괄호

n =>                          // 여러 줄이면 중괄호와 return
{
    int r = n * 2;
    return r + 1;
}
```

한 줄이면 `return` 이 필요 없고, 중괄호를 열면 `return` 을 적어야 합니다.
헷갈리기 쉬운데 규칙은 단순합니다. **중괄호를 열면 메서드처럼 적는다** 입니다.

담을 때도 씁니다.

```csharp
Func<int, int> twice = n => n * 2;
Console.WriteLine(twice(5));      // 10
```

## 바깥 변수를 데리고 다닌다

람다에는 특이한 성질이 하나 있습니다.

```csharp
int limit = 10;

Func<int, bool> over = n => n > limit;

Console.WriteLine(over(15));    // True
```

`limit` 은 람다 밖에 있는 변수인데 안에서 씁니다.
람다는 **만들어질 때 주변에 있던 변수를 같이 챙겨 갑니다.**

그래서 이런 것도 됩니다.

```csharp
Func<int, bool> MakeOver(int limit)
{
    return n => n > limit;
}

var over10 = MakeOver(10);
var over100 = MakeOver(100);
```

`MakeOver` 는 이미 끝났는데 `over10` 은 `limit` 이 10인 것을 기억하고 있습니다.
같은 코드로 서로 다르게 동작하는 것을 여러 개 찍어낸 셈입니다.

앞에서 지역 변수는 메서드가 끝나면 사라진다고 했습니다.
람다가 데려간 변수는 예외입니다. 람다가 살아 있는 동안 같이 살아남습니다.
컴파일러가 그 변수를 힙으로 옮겨 두기 때문입니다.

편한데 함정도 있습니다. **값이 아니라 변수를 데려갑니다.**

```csharp
int n = 1;
Action print = () => Console.WriteLine(n);

n = 99;
print();      // 1 이 아니라 99
```

만들 때의 값이 아니라 **부를 때의 값**이 나옵니다.
반복문 안에서 람다를 만들어 모아 두면 이것 때문에 놀라는 일이 생깁니다.

## 컬렉션에 넘기면 반복문이 사라진다

`List` 에는 람다를 받는 메서드가 여럿 있습니다.

```csharp
var nums = new List<int> { 5, -3, 12, 8, -1 };

nums.RemoveAll(n => n < 0);            // 음수 전부 삭제
var found = nums.Find(n => n > 10);    // 조건에 맞는 첫 번째
bool any = nums.Exists(n => n > 100);  // 하나라도 있는가
nums.Sort((a, b) => b - a);            // 내림차순으로 정렬
```

`using System.Linq;` 를 붙이면 더 많아집니다.

```csharp
var big = nums.Where(n => n > 5);              // 조건에 맞는 것만
var names = dogs.Select(d => d.Name);          // 원하는 것만 뽑기
int sum = nums.Sum();
var sorted = dogs.OrderBy(d => d.Age);         // 나이순 정렬
```

전부 **어떻게 반복할지가 아니라 무엇을 할지만** 적습니다.
반복문이 사라진 것이 아니라 안으로 들어간 것입니다.

```csharp
var result = new List<int>();
foreach (var n in nums) if (n > 5) result.Add(n);
```

```csharp
var result = nums.Where(n => n > 5).ToList();
```

두 코드가 같은 일을 합니다. 아래쪽은 **조건 하나만** 적혀 있어서 읽을 것이 적습니다.

다만 짧다고 항상 나은 것은 아닙니다.
길게 이어 붙이면 오히려 읽기 어려워지고, 반복문 하나면 될 일에 여러 번 도는 경우도 생깁니다.

## 정리

- 람다는 이름 없이 그 자리에서 만드는 메서드입니다.
- 매개변수, 화살표, 본문 셋뿐입니다. 알아낼 수 있는 것은 전부 생략합니다.
- 한 줄이면 `return` 이 없고, 중괄호를 열면 메서드처럼 적습니다.
- 바깥 변수를 데려갑니다. 메서드가 끝나도 그 변수는 살아남습니다.
- 값이 아니라 변수를 데려갑니다. 부를 때의 값이 나옵니다.
- 컬렉션 메서드에 넘기면 반복문 대신 조건만 적게 됩니다.
- 짧다고 늘 나은 것은 아닙니다. 길게 이어지면 반복문이 읽기 쉬울 때도 있습니다.