포스트

C#의 Predicate

Predicate 델리게이트는 Func<>Action<>과 같은 미리 정의된 델리게이트 형식입니다.

Predicate<T> 델리게이트는 특정 조건에 맞는지를 검사하는 메서드를 캡슐화하는 데 사용되는 델리게이트로, 하나의 매개변수를 갖고 리턴 값이 bool인 델리게이트입니다.

1
public delegate bool Predicate<in T>(T obj);

사용 예제

Predicate<T> 델리게이트는 입력 값이 하나이고, 특정 조건에 맞는지 검사하는 메서드를 정의할 때 사용합니다.

이전에 익명 델리게이트에 대한 글을 읽어보셨다면, delegate로 만들었던 Predicate를 볼 수 있었을 수도 있습니다.
이전 예제를 가져오면, 아래와 같이 Predicate를 임의로 만들어 정의하고 있었습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public delegate bool Predicate<T>(T x);

static class Utilities
{
    public static int Count<T>(IEnumerable<T> items, Predicate<T> predMethod)
    {
        int count = 0;
        foreach (var item in items)
        {
            if (predMethod(item))
            {
                count++;
            }
        }
        return count;
    }
}

internal class Program
{
	static void Main(string[] args)
	{
		var numbers = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9};
		
		int oddNumbers = Utilities.Count(numbers, delegate(int n) { return n % 2 != 0; });
		Console.WriteLine(oddNumbers); // 5
		
		int evenNumbers = Utilities.Count(numbers, delegate(int n) { return n % 2 == 0; });
		Console.WriteLine(evenNumbers); // 4
	}
}

위 예제에서 임의로 만들었던 Predicate<T> 델리게이트를 제거하고, 익명 델리게이트도 람다로 바꿔보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
static class Utilities
{
    public static int Count<T>(IEnumerable<T> items, Predicate<T> predMethod)
    {
        int count = 0;
        foreach (var item in items)
        {
            if (predMethod(item))
            {
                count++;
            }
        }
        return count;
    }
}

internal class Program
{
    static void Main(string[] args)
    {
        var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        
        Console.WriteLine(Utilities.Count(numbers, n => n % 2 != 0)); // 5
        Console.WriteLine(Utilities.Count(numbers, n => n % 2 == 0)); // 4
    }
}

훨씬 깔끔하고 보기 좋게 만들 수 있었습니다.


Predicate<T>는 기존의 컬렉션 매개변수에서도 자주 볼 수 있는 델리게이트입니다.

예를 들어, List<T>FindAll()이라는 메서드도 이 델리게이트를 사용합니다.

1
2
public List<T> FindAll(Predicate<T> match)
{}
1
2
3
4
5
6
static void Main(string[] args)
{
  // FindAll()에 람다식을 넘겨 줌
  var result = numbers.FindAll(n => n % 2 == 0);
  Console.WriteLine(string.Join(", ", result)); // 2, 4, 6, 8
}

FindAll 외에도 Exists, Find, FindLast, RemoveAll, 등에서도 사용됩니다.

이렇게, 메서드들에서 Predicate<T>라는 매개변수를 발견하게 된다면, 특정 조건에 맞는지 검사하는 메서드를 정의하고 이를 넘겨주면 되겠습니다.


참고

[delegate] 01.델리게이트의 정의와 정체, 체이닝, 사용 목적

[delegate] 03. 익명 델리게이트와 Func, Action

C#의 람다(Lambda)와 캡처(Capture), 클로저(closure)

이 기사는 저작권자의 CC BY-NC-ND 4.0 라이센스를 따릅니다.