Tip
소프트웨어 개발이 새로운가요? 먼저 시작하기 자습서부터 시작하세요. 람다 식을 사용하기 전에 핵심 형식 및 메서드 기술을 빌드합니다.
경우에 따라 작은 동작 조각인 함수를 다른 메서드에 직접 전달하려고 합니다. 예를 들어 목록을 필터링할 수 있지만 필터링 조건은 상황에 따라 변경됩니다. 가능한 모든 조건에 대해 별도의 명명된 메서드를 작성하는 대신 조건 자체를 인수로 전달합니다.
람다 식은 C#의 기능으로 이것을 가능하게 합니다. 람다 식은 이름을 지정하지 않고 작성하는 컴팩트한 인라인 함수입니다. 화살표 연산 => 자를 사용하여 매개 변수 목록을 본문과 구분합니다.
x => x * 2
왼쪽에서 오른쪽으로 읽기: x 입력 매개 변수, => "이동"을 의미하며 x * 2 본문입니다. 반환된 값을 계산합니다. 매개 변수가 없거나 둘 이상인 경우 괄호로 래핑합니다. () => 42 또는 (left, right) => left + right.
대리자는 람다 식을 지원합니다.
람다 식을 사용하려면 C# 컴파일러가 매개 변수 형식과 반환 형식의 두 가지를 알고 있어야 합니다. 매개 변수 형식과 반환 형식을 대리자 형식이라고 합니다.
대리자 형식은 메서드 시그니처를 나타내는 형식입니다. 대리자 형식의 변수는 매개 변수 형식과 반환 형식이 일치하는 한 람다 식 또는 명명된 메서드와 같은 일치하는 메서드를 보유할 수 있습니다.
키워드를 사용하여 대리자 형식을 선언합니다.delegate
delegate int Transform(int value);
이 선언은 "Transform 를 수락 int 하고 반환하는 메서드의 대리자 형식입니다 int." 그런 다음, 람다 식 또는 명명된 메서드를 해당 형식의 변수에 할당할 수 있습니다.
Transform doubler = x => x * 2; // assign a lambda expression
Transform squarer = Square; // assign a named method
Console.WriteLine(doubler(5)); // 10
Console.WriteLine(squarer(5)); // 25
static int Square(int value) => value * value;
doubler와 squarer 모두 Transform 유형의 값을 갖습니다. 일반 메서드와 똑같이 호출합니다. 컴파일러는 할당하는 항목이 선언된 서명과 일치하는지 확인합니다.
기본 제공 대리자 형식: Func 및 Action
모든 상황에 대해 사용자 지정 대리자 형식을 선언하는 것은 반복적일 수 있습니다. .NET 대부분의 시나리오를 다루는 제네릭 대리자 형식(Func 및 Action)의 두 패밀리를 제공하므로 delegate 키워드를 직접 사용할 필요가 거의 없습니다.
두 패밀리 모두 0~16개의 입력 형식 매개 변수가 있는 버전으로 제공되며, 따라서 입력 수에 맞게 확장됩니다. 두 패밀리의 주요 차이점은 다음과 같습니다.
-
System.Func<T,TResult> (및
Func<T1, T2, TResult>등)는 값을 반환하는 메서드를 나타냅니다. 마지막 형식 매개 변수는 항상 반환 형식입니다. 모든 이전 항목은 입력 형식입니다. -
System.Action<T> (및
Action<T1, T2>등)는 아무 것도 반환하지 않는 메서드를void나타냅니다. 모든 형식 매개 변수는 입력 형식입니다. System.Action 형식 매개 변수가 없는 경우 입력이 없고 반환 값이 없는 메서드를 나타냅니다.
예를 들어 두 Func<int, int, int> 개의 int 입력과 하나의 int 결과가 있는 메서드를 설명합니다.
Action<string> 는 하나의 string 입력과 반환 값이 없는 메서드를 설명합니다.
Func<int, int, int> add = (left, right) => left + right;
Action<string> report = message => Console.WriteLine($"Report: {message}");
int total = add(5, 9);
report($"5 + 9 = {total}");
판독기에서 전체 메서드 본문을 검사하지 않고 의도를 이해할 수 있도록 람다에서 설명이 포함된 매개 변수 이름을 사용합니다.
메서드에 람다 식 전달
메서드가 a 또는 Func 매개 변수를 Action 선언하면 호출자는 해당 대리자 형식과 일치하는 람다 식을 전달합니다. 컴파일러는 람다의 매개 변수 형식 및 반환 형식이 선언된 대리자 형식과 일치하는지 확인합니다. 일치하지 않으면 코드가 컴파일되지 않습니다.
int[] numbers = [1, 2, 3, 4, 5, 6];
int[] evenNumbers = Filter(numbers, value => value % 2 == 0).ToArray();
Console.WriteLine(string.Join(", ", evenNumbers));
메서드는 Filter 라는 Func<int, bool>매개 변수를 predicate 선언 합니다. 이 Func<int, bool> 형식은 호출자에게 하나의 int 입력과 하나의 bool 결과라는 예상되는 형태를 알려줍니다. 호출자가 value => value % 2 == 0을 해당 인수로 전달합니다. 이 패턴은 LINQ 및 여러 .NET API 전체에 나타납니다.
람다 표현식을 독립적으로 유지하세요
람다 식은 주변 코드의 변수를 참조할 수 있습니다. 캡처는 람다가 자체 본문 외부에 선언된 변수에 대한 참조를 보유한다는 것을 의미합니다. 람다와 캡처하는 변수의 조합을 클로저라고 합니다.
아무것도 캡처할 필요가 없는 경우 한정자를 람다에 추가 static 합니다. 정적 람다는 본문 내에 선언된 자체 매개 변수 및 값만 사용할 수 있습니다. 바깥쪽 범위에서 인스턴스 상태나 지역 변수를 캡처하지 못합니다.
Func<int, bool> isEven = static value => value % 2 == 0;
Console.WriteLine(isEven(14));
Console.WriteLine(isEven(15));
정적 람다는 의도를 명확하게 하고 우발적인 캡처를 방지합니다.
입력이 관련이 없는 경우 무시 매개 변수 사용
대리자 서명에 필요하지 않은 매개 변수가 포함된 경우가 있습니다. 취소 _ 를 사용하여 해당 선택을 명시적으로 알립니다.
일반적인 예로는 sender나 EventArgs를 사용하지 않는 이벤트 처리기, 여러 입력 중 일부만 필요한 콜백, 그리고 사용하지 않는 인덱스를 제공하는 LINQ 오버로드가 있습니다.
Action<int, int, string> statusUpdate = (_, _, message) => Console.WriteLine(message);
statusUpdate(200, 42, "Operation completed");
삭제하면 중요한 매개 변수가 표시되므로 가독성이 향상됩니다.
이벤트는 선택적 알림을 제공합니다.
이벤트는 한 개체(게시자)가 다른 개체(구독자)에게 문제가 발생할 때 알리는 데 사용하는 메커니즘입니다. 게시자는 수신 대기 중인 사용자 또는 구독자 수를 알 필요가 없습니다. 구독자는 옵트인하도록 선택합니다.
이벤트는 대리자를 기반으로 빌드됩니다. 이벤트는 event 키워드에 의해 적용되는 추가 제한 사항이 있는 대리자 필드입니다. 외부 코드는 이벤트에 구독(+=)하거나 구독 취소(-=)만 할 수 있습니다. 이벤트를 선언하는 클래스만 이벤트를 발생시킬 수 있습니다.
이벤트 대리자 형식에 대한 .NET 규칙은 System.EventHandler<TEventArgs>이며, 여기서 T 알림에 포함된 데이터 형식입니다. 해당 서명에는 항상 두 개의 매개 변수 sender (이벤트를 발생시킨 개체)와 형식 T의 이벤트 데이터가 있습니다.
MessagePublisher publisher = new();
publisher.MessagePublished += (_, message) => Console.WriteLine($"Received: {message}");
publisher.Publish("Records updated");
코드 탐색:
-
MessagePublisher를 선언합니다.event EventHandler<string>? MessagePublished키워드는event호출자가 구독하거나 구독을 취소할 수 있다는 것을 의미하며 직접 호출할 수 없습니다. -
publisher.MessagePublished += (_, message) => ...람다 식을 사용하여 구독합니다. 이_는 필요하지 않은 매개변수sender를 무시합니다. -
publisher.Publish("Records updated")는 이벤트를 발생시키고 구독된 모든 처리기를 실행합니다.
구독은 선택 사항입니다. 이 ?.Invoke(...) 메서드의 Publish 경우 하나 이상의 구독자가 연결된 경우에만 이벤트가 발생합니다. 게시자는 누군가가 듣고 있는지 알지도 신경 쓰지도 않고 이벤트를 발생시킵니다.
참고하십시오
.NET