C # Lambda 표현식 : 왜 사용해야합니까?


309

Microsoft Lambda Expression 설명서를 빨리 읽었습니다 .

그러나 이런 종류의 예는 다음과 같이 더 잘 이해하는 데 도움이되었습니다.

delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25

그래도 왜 그런 혁신인지 이해할 수 없습니다. "메소드 변수"가 끝나면 죽는 방법 일뿐입니다. 실제 방법 대신 왜 이것을 사용해야합니까?


3
이 페이지에 와서 무엇을 모르고있는 당신의 그것들을 위해 delegateC #으로, 나는 매우 이것을 읽고 제안 하기 전에 :이 페이지의 나머지 부분을 읽기 stackoverflow.com/questions/2082615/...
계산법 협곡을

답변:


281

람다 식은 익명 대리자의 간단한 구문이며 익명 대리자가 사용될 수있는 모든 곳에서 사용할 수 있습니다. 그러나 그 반대는 사실이 아닙니다. 람다 식은 LINQ to SQL과 같은 많은 마법을 허용하는 식 트리로 변환 될 수 있습니다.

다음은 익명 대리자를 사용하고 람다 식을 사용하여 LINQ to Objects 표현식 의 예입니다 .

// anonymous delegate
var evens = Enumerable
                .Range(1, 100)
                .Where(delegate(int x) { return (x % 2) == 0; })
                .ToList();

// lambda expression
var evens = Enumerable
                .Range(1, 100)
                .Where(x => (x % 2) == 0)
                .ToList();

Lambda 표현식과 익명 델리게이트는 별도의 함수를 작성하는 것보다 이점 이 있습니다. 클로저 를 구현 하면 함수에 매개 변수추가 하거나 일회용 객체를 만들지 않고도 로컬 상태를 함수전달할 수 있습니다.

식 트리는 C # 3.0의 매우 강력한 새로운 기능으로, API가 실행할 수있는 메서드에 대한 참조를 얻는 대신 식의 구조를 볼 수 있도록합니다. API는 대리자 매개 변수를 매개 변수로 만들면 Expression<T>컴파일러가 익명 ​​대리자 대신 람다에서 식 트리를 생성합니다.

void Example(Predicate<int> aDelegate);

처럼 호출 :

Example(x => x > 5);

된다 :

void Example(Expression<Predicate<int>> expressionTree);

후자는 표현식을 설명하는 추상 구문 트리 의 표현을 전달 받게됩니다 x > 5. LINQ to SQL은 C # 표현식을 서버 측에서 필터링 / 순서 등으로 원하는 SQL 표현식으로 변환 할 수 있도록이 동작에 의존합니다.


1
클로저가 없으면 정적 메서드를 콜백으로 사용할 수 있지만 일부 클래스에서는 이러한 메서드를 정의해야하므로 의도 된 사용 범위를 넘어서서 이러한 메서드의 범위가 거의 확실하게 증가해야합니다.
DK.

10
FWIW, 익명 대리자와 폐쇄 할 있으므로 람다는 엄격하게 필요하지 않습니다. 람다는 익명의 대리인보다 눈에 잘 띄게 읽을 수 있으며 Linq를 사용하지 않으면 눈이 번질 수 있습니다.
Benjol

138

익명 함수 및 표현식은 전체 메소드를 작성하는 데 필요한 추가 작업의 이점이없는 일회성 메소드에 유용합니다.

이 예제를 고려하십시오.

 string person = people.Find(person => person.Contains("Joe"));

 public string FindPerson(string nameContains, List<string> persons)
 {
     foreach (string person in persons)
         if (person.Contains(nameContains))
             return person;
     return null;
 }

이들은 기능적으로 동일합니다.


8
이 람다 식을 처리하기 위해 Find () 메서드는 어떻게 정의 되었습니까?
Patrick Desjardins

3
Predicate <T>는 Find 메서드가 기대하는 것입니다.
Darren Kopp

1
내 람다식이 Predicate <T>의 계약과 일치하므로 Find () 메서드가이를 수락합니다.
Joseph Daigle

"string person = people.Find (persons => persons.Contains ("Joe "));"을 (를) 찾으셨습니까?
Gern Blanston

5
@FKCoder, 아니, 그는 "string person = people.Find (p => p.Contains ("Joe "));
Benjol

84

다른 컨트롤을 사용하여 일부 컨트롤의 이벤트에 대한 핸들러를 선언하려는 상황에서 유용하다는 것을 알았습니다. 일반적으로 컨트롤의 참조를 클래스의 필드에 저장하여 생성 된 것과 다른 방법으로 사용할 수 있도록해야합니다.

private ComboBox combo;
private Label label;

public CreateControls()
{
    combo = new ComboBox();
    label = new Label();
    //some initializing code
    combo.SelectedIndexChanged += new EventHandler(combo_SelectedIndexChanged);
}

void combo_SelectedIndexChanged(object sender, EventArgs e)
{
    label.Text = combo.SelectedValue;
}

람다 식 덕분에 다음과 같이 사용할 수 있습니다.

public CreateControls()
{
    ComboBox combo = new ComboBox();
    Label label = new Label();
    //some initializing code
    combo.SelectedIndexChanged += (s, e) => {label.Text = combo.SelectedValue;};
}

훨씬 쉽게.


첫 번째 예에서 발신자를 전송하고 값을 가져 오지 않는 이유는 무엇입니까?
앤드류

@Andrew :이 간단한 예제에서는 보낸 사람을 사용할 필요가 없습니다. 문제의 구성 요소가 하나만 있고 필드를 사용하면 캐스트를 직접 저장하므로 선명도가 향상됩니다. 실제 시나리오에서는 개인적으로 발신자를 대신 사용하는 것을 선호합니다. 일반적으로 가능한 경우 여러 이벤트에 대해 하나의 이벤트 핸들러를 사용하므로 실제 발신자를 식별해야합니다.
Chris Tophski

35

Lambda는 C # 2.0의 익명 대리자 구문을 정리했습니다.

Strings.Find(s => s == "hello");

C # 2.0에서 다음과 같이 수행되었습니다.

Strings.Find(delegate(String s) { return s == "hello"; });

기능적으로 그들은 똑같은 일을합니다. 단지 훨씬 간결한 구문입니다.


3
그들은 아니에요 확실히 같은 일 - @Neil 윌리엄스 지적 익명의 방법이 같은 방식을 사용할 수없는 반면에, 당신은 식 트리를 사용하여 람다 'AST를 추출 할 수 있습니다.
ljs

이것은 람다의 다른 많은 장점 중 하나입니다. 익명 메소드보다 코드를 더 잘 이해하는 데 도움이됩니다. 분명히 람다를 만들려는 의도는 아니지만 더 자주 사용할 수있는 시나리오입니다.
Guruji

29

이것은 람다 식을 사용하는 한 가지 방법입니다. 델리게이트를 사용할 수있는 곳이면 람다 식을 사용할 수 있습니다. 이를 통해 다음과 같은 작업을 수행 할 수 있습니다.

List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");

strings.Find(s => s == "hello");

이 코드는 "hello"단어와 일치하는 항목을 목록에서 검색합니다. 이를 수행하는 다른 방법은 실제로 다음과 같이 대리자를 Find 메서드에 전달하는 것입니다.

List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");

private static bool FindHello(String s)
{
    return s == "hello";
}

strings.Find(FindHello);

편집 :

C # 2.0에서는 익명 대리자 구문을 사용하여이 작업을 수행 할 수 있습니다.

  strings.Find(delegate(String s) { return s == "hello"; });

람다는 구문을 크게 정리했습니다.


2
@Jonathan Holland : 익명 대리자 구문을 편집하고 추가해 주셔서 감사합니다. 예제를 잘 완성했습니다.
Scott Dorman

익명 대리자는 무엇입니까? // 죄송합니다. 저는 C #을 처음 사용합니다
HackerMan

1
@HackerMan, 익명 대리자를 "이름"이없는 함수로 생각하십시오. 여전히 입력 및 출력을 가질 수있는 함수를 정의하지만 이름이므로 직접 참조 할 수 없습니다. 위에 표시된 코드 에서 메서드 자체를 매개 변수로 메서드를 정의하고 (a string를 반환하고 bool) 반환 Find합니다.
Scott Dorman

22

Microsoft는 Lambda 식이라는 익명의 대리자를 만드는보다 깨끗하고 편리한 방법을 제공했습니다. 그러나, 이 진술 의 표현 부분 에는 많은주의를 기울이지 않습니다 . Microsoft는 람다 식을 기반으로 식 트리를 만드는 클래스가 포함 된 전체 네임 스페이스 인 System.Linq.Expressions를 릴리스했습니다 . 식 트리는 논리를 나타내는 개체로 구성됩니다. 예를 들어 x = y + z는 .Net의 표현식 트리에 포함될 수있는 표현식입니다. 다음 (간단한) 예를 고려하십시오.

using System;
using System.Linq;
using System.Linq.Expressions;


namespace ExpressionTreeThingy
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<Func<int, int>> expr = (x) => x + 1; //this is not a delegate, but an object
            var del = expr.Compile(); //compiles the object to a CLR delegate, at runtime
            Console.WriteLine(del(5)); //we are just invoking a delegate at this point
            Console.ReadKey();
        }
    }
}

이 예는 사소한 것입니다. 그리고 "당신은 표현식을 만들고 런타임에 컴파일하는 대신 델리게이트를 직접 만들 수 있었기 때문에 쓸모가 없습니다"라고 생각하고 있습니다. 그리고 당신은 옳을 것입니다. 그러나 이것은 표현 트리의 기초를 제공합니다. Expressions 네임 스페이스에는 여러 가지식이 있으며 자신 만의 식을 만들 수 있습니다. 디자인이나 컴파일 타임에 알고리즘이 무엇인지 정확히 모르는 경우 이것이 유용 할 수 있다고 생각합니다. 과학 계산기를 작성하기 위해 이것을 사용하는 어딘가의 예를 보았습니다. 베이지안 시스템이나 유전자 프로그래밍 에도 사용할 수 있습니다(일체 포함). 내 경력에서 몇 번이나 Excel과 비슷한 기능을 작성하여 사용 가능한 데이터를 조작 할 수있는 간단한 표현 (추가, 서브 트리 등)을 입력 할 수있었습니다. .Net 3.5 이전에는 C # 외부의 일부 스크립팅 언어에 의존했거나 즉시 코드 생성 기능을 사용하여 .Net 코드를 즉시 작성해야했습니다. 이제 표현 트리를 사용하겠습니다.


12

특정 장소에서 한 번만 사용되는 메소드를 사용하는 장소에서 멀리 떨어져 정의하지 않아도됩니다. 정렬과 같은 일반적인 알고리즘의 비교기로 사용하면 정렬을 호출하기 위해 다른 곳을 보도록 강요하지 않고 정렬을 호출하는 사용자 정의 정렬 함수를 정의 할 수 있습니다.

그리고 그것은 실제로 혁신이 아닙니다. LISP는 약 30 년 이상 람다 기능을 가지고 있습니다.


6

또한 메서드에 작용하는 일반 코드를 작성할 때 람다 식을 사용하는 방법을 찾을 수 있습니다.

예를 들면 다음과 같습니다. 메소드 호출에 걸리는 시간을 계산하는 일반 함수. (즉 Action여기에)

public static long Measure(Action action)
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    action();
    sw.Stop();
    return sw.ElapsedMilliseconds;
}

다음과 같이 람다 식을 사용하여 위의 메소드를 호출 할 수 있습니다.

var timeTaken = Measure(() => yourMethod(param));

Expression을 사용하면 메소드 및 반환 매개 변수에서 반환 값을 얻을 수 있습니다

var timeTaken = Measure(() => returnValue = yourMethod(param, out outParam));

5

람다 식은 익명의 메서드를 나타내는 간결한 방법입니다. 익명 메소드와 Lambda 표현식 모두 메소드 구현을 인라인으로 정의 할 수 있지만 익명 메소드는 매개 변수 유형과 메소드의 리턴 유형을 명시 적으로 정의해야합니다. Lambda 식은 C # 3.0의 형식 유추 기능을 사용하여 컴파일러가 컨텍스트를 기반으로 변수의 형식을 유추 할 수 있습니다. 그것은 우리에게 많은 타이핑을 저장하기 때문에 매우 편리합니다!


5

람다 식은 대리자 인스턴스 대신 작성된 익명 메서드와 같습니다.

delegate int MyDelagate (int i);
MyDelagate delSquareFunction = x => x * x;

람다 표현을 고려하십시오 x => x * x;

입력 매개 변수 값은 x (왼쪽 ==)입니다.

함수 논리는 x * x입니다 (오른쪽 =>).

람다 식의 코드는 식 대신 문 블록 일 수 있습니다.

x => {return x * x;};

참고 : Func사전 정의 된 일반 위임입니다.

    Console.WriteLine(MyMethod(x => "Hi " + x));

    public static string MyMethod(Func<string, string> strategy)
    {
        return strategy("Lijo").ToString();
    }

참고 문헌

  1. 델리게이트와 인터페이스를 어떻게 상호 교환하여 사용할 수 있습니까?

4

많은 경우에 한 곳에서만 기능을 사용하므로 메소드를 작성하면 클래스가 복잡해집니다.


3

작은 작업을 수행하고 사용 위치에 가까운 변수를 선언하는 것과 달리 사용되는 위치에 매우 가깝게 배치하는 방법입니다. 이것은 코드를 더 읽기 쉽게 만들어야합니다. 표현식을 익명화함으로써, 함수가 다른 곳에서 사용되어 "향상"되도록 클라이언트 코드가 변경되는 경우 누군가가 클라이언트 코드를 깨뜨리기가 훨씬 어려워집니다.

마찬가지로 foreach를 사용해야하는 이유는 무엇입니까? 일반 for 루프를 사용하거나 IEnumerable을 직접 사용하여 foreach에서 모든 작업을 수행 할 수 있습니다. 답변 : 당신이하지 않는 필요 로하지만, 그것은 당신의 코드를 읽기 수 있습니다.


0

혁신은 유형 안전과 투명성에 있습니다. 람다 식의 유형을 선언하지는 않지만 유추되며 코드 검색, 정적 분석, 리팩토링 도구 및 런타임 반영에 사용될 수 있습니다.

예를 들어, 해커가 일반적으로 예상했던 문자열을 전달했기 때문에 SQL을 사용하고 SQL 주입 공격을받을 수 있기 전에. 이제 LINQ 람다 식을 사용합니다.

순수한 델리게이트에서 LINQ API를 빌드 할 수 없습니다. 표현식 트리를 평가하기 전에 함께 결합해야하기 때문입니다.

2016 년에 대부분의 인기있는 언어는 람다 식 지원을 제공하며 C #은 주류 명령형 언어 중에서이 진화의 선구자 중 하나였습니다.


0

이것은 람다 식을 사용하는 이유에 대한 가장 좋은 설명 일 것입니다-> https://youtu.be/j9nj5dTo54Q

요약하면 코드 가독성을 향상시키고 코드를 복제하지 않고 재사용함으로써 오류 발생 가능성을 줄이고 뒤에서 발생하는 최적화를 활용합니다.


0

람다 식과 익명 함수의 가장 큰 이점은 라이브러리 / 프레임 워크의 클라이언트 (프로그래머)가 지정된 라이브러리 / 프레임 워크 (LINQ, ASP.NET Core 및 다른 많은 방법들)은 일반적인 방법으로는 불가능합니다. 그러나 이들의 장점은 단일 응용 프로그램 프로그래머에게는 분명하지 않지만 나중에 라이브러리 코드의 동작을 구성하려는 라이브러리 또는 라이브러리를 사용하는 다른 사용자가 사용할 라이브러리를 작성하는 개발자에게는 분명합니다. 따라서 람다 식을 효과적으로 사용하는 맥락은 라이브러리 / 프레임 워크의 사용 / 생성입니다.

또한 일회성 사용 코드를 설명하므로 더 많은 코드를 복잡하게 만드는 클래스의 멤버 일 필요는 없습니다. 클래스 객체의 작업을 구성하려고 할 때마다 명확하지 않은 클래스를 선언해야한다고 상상해보십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.