2008-10-03 15 views
273

나는 Microsoft Lambda Expression 문서를 빨리 ​​읽었습니다. C# 람다 식 : 왜 사용해야합니까?

예를 들어 이런 종류의

날하지만, 더 잘 이해하는 데 도움이 있습니다 : 그것은 그러한 혁신을 왜 아직

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

, 나는 이해가 안 돼요. 그것은 "메소드 변수"가 끝날 때 죽는 방법 일뿐입니다. 맞습니까? 실제 방법 대신 이걸 사용해야하는 이유는 무엇입니까?

답변

256

Lambda expressions은 익명 대리자의보다 간단한 구문이며 익명 대리자를 사용할 수있는 모든 곳에서 사용할 수 있습니다. 그러나 그 반대는 사실이 아닙니다. 람다 식은 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(); 

람다 표현식과 익명의 대의원 별도의 함수를 작성을 통해 이점을 가지고 : closures을 구현하여 함수에 pass local state to the function without adding parameters을 허용하거나 일회용 개체를 만들 수 있습니다.

Expression trees은 C# 3.0의 매우 강력한 새로운 기능으로 API는 실행 가능한 메서드에 대한 참조를 얻는 대신 표현식의 구조를 볼 수 있습니다.

Example(x => x > 5); 

이된다 : API를 그냥 Expression<T> 매개 변수에 위임 매개 변수를 확인하는 컴파일러 대신 익명 대리자 람다에서 식 트리를 생성합니다 같은

void Example(Predicate<int> aDelegate); 

라는

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

후자는 표현 x > 5을 설명하는 abstract syntax tree의 표현을 전달합니다. LINQ to SQL은이 동작을 사용하여 C# 식을 서버 측에서 필터링/주문/기타에 필요한 SQL 식으로 변환 할 수 있습니다. 그들은 똑같은 일을, 기능적으로

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

:

+0

클로저가 없으면 정적 메서드를 콜백으로 사용할 수 있지만 여전히 이러한 메서드를 의도 된 사용 범위를 넘어서는 범위에서 증가시키면서 특정 클래스에서 이러한 메서드를 정의해야합니다. –

+10

FWIW, 익명의 대리인과 함께 폐쇄 할 수 있으므로 엄격하게 람다가 필요하지 않습니다.람다 (Lambda)는 익명의 대표자보다 읽기 쉽습니다. Linq를 사용하면 눈이 피가 날 것입니다. – Benjol

4

많은 경우, 한 곳에서만 기능을 사용하므로 메서드를 만드는 것은 클래스를 혼란스럽게합니다.

11

한 번만 특정 장소에서 사용되는 메소드를 사용하는 장소에서 멀리 정의하지 않아도됩니다. 좋은 용도는 정렬과 같은 일반 알고리즘의 비교 자로 사용됩니다. 사용자 정의 정렬 기능을 정의 할 수 있습니다. 여기서 사용자 정의 정렬 기능을 정의 할 수 있습니다.이 기능을 사용하면 다른 곳을보고 정렬하려는 항목을 보도록 강요하지 않고 정렬을 호출 할 수 있습니다.

사실 혁신이 아닙니다. LISP는 약 30 년 이상 람다 기능을 가지고 있습니다.

124

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

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; 
} 

대이 기능적으로 동일합니다

이 예를 생각해 보자.

+6

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

+1

술어 은 Find 메소드가 예상하는 것입니다. –

+1

내 lambda 표현식이 술부 에 대한 계약과 일치하므로 Find() 메소드는이를 수용합니다. –

3

작은 동작을 취하고 사용 위치에 매우 가깝게 두는 방법입니다 (사용 지점에 가까운 변수 선언과 달리). 이것은 당신의 코드를 더 읽기 쉽게 만들어야한다. 익스프레션을 익명화함으로써 함수가 다른 곳에서 사용되어 "강화"되도록 수정 된 경우 누군가가 클라이언트 코드를 해독하는 것이 더 어려워집니다.

마찬가지로 foreach를 사용해야합니까? foreach 루프를 사용하거나 IEnumerable을 직접 사용하여 모든 것을 처리 할 수 ​​있습니다. 대답 : 당신은 이 필요하지 않습니다.이 필요합니다.하지만 코드가 더 읽기 쉽습니다.

4

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

27

이것은 람다 식을 사용하는 한 가지 방법 일뿐입니다. 당신은 람다 식 어디서나을 사용할 수 있습니다. 위임자를 사용할 수 있습니다. 이렇게하면 다음과 같은 작업을 수행 할 수 있습니다.

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"단어와 일치하는 항목을 검색합니다.

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); 

편집 :이 작업을 수행하는 다른 방법은 실제로 다음과 같이 Find 메서드에 대리자를 전달하는 것입니다

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

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

람다 (Lambda 's)는 구문을 상당히 정리했습니다.

+0

더 알아 내기 시작합니다! Thx –

+2

@Jonathan Holland : 익명의 대리자 구문을 편집하고 추가해 주셔서 감사합니다. 예제를 멋지게 완성합니다. –

+0

익명 대리인이란 무엇입니까? // 미안 해요. C# – HackerMan

33

람다의 정리 C# 2.0의 익명의 대리인이 구문은 ...

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

예를

에 대한이 같은 C# 2.0에서 이루어졌다 그것의 훨씬 더 간결한 구문.

+3

@Neil Williams가 지적한 것처럼, 익명 메소드는 같은 방식으로 사용할 수 없지만 표현식 트리를 사용하여 람다의 AST를 추출 할 수 있습니다. – ljs

21

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(); 
     } 
    } 
} 

이 예제는 간단합니다. 표현식을 작성하고 런타임에 컴파일하는 대신 델리게이트를 직접 만들 수 있기 때문에 이것은 쓸모가 없습니다. 그리고 당신이 옳을 것입니다. 그러나 이것은 표현 트리의 토대를 제공합니다. 표현식 네임 스페이스에는 여러 가지 표현식이 있으며 자신 만의 표현식을 만들 수 있습니다. 이 알고리즘은 디자인이나 컴파일시에 알고리즘이 무엇인지 정확히 모를 때 유용 할 수 있습니다. 이걸 사용하여 과학적인 계산기를 작성한 예를 보았습니다. Bayesian 시스템 또는 genetic programming (AI) 시스템에도 사용할 수 있습니다. 몇 년 동안 필자는 Excel과 유사한 기능을 작성해야만 사용자가 간단한 표현 (추가, 자막 등)을 입력하여 사용 가능한 데이터를 조작 할 수있었습니다. 사전 - 닷넷 3.5에서 나는 C#의 외부 스크립팅 언어에 의지해야했으며, 리플렉션에서 코드 방출 기능을 사용하여 .Net 코드를 즉시 작성해야했습니다. 이제 표현식 트리를 사용할 것입니다.

79

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

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;}; 
} 

훨씬 쉽습니다.

+16

실제 사용 예 +1 – Nipuna

+0

첫 번째 예에서는 발신자를 전송하고 값을 가져 오는 것이 좋습니다. – Andrew

+0

@ 앤드류 :이 간단한 예제에서는 문제의 구성 요소가 하나뿐이기 때문에 송신자를 사용할 필요가 없으며 필드를 사용하여 직접 캐스트를 저장하므로 명확성이 향상됩니다. 실제 시나리오에서는 개인적으로 발신자를 대신 사용하는 것을 선호합니다. 일반적으로 가능한 경우 여러 이벤트에 대해 하나의 이벤트 처리기를 사용하므로 실제 보낸 사람을 식별해야합니다. –

4

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

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

는 람다 식 x => x * x;

The input parameter value is x (on the left side of =>)

The function logic is x * x (on the right side of =>)

람다 식의 코드가 문 블록 대신의 표현이 될 수를 고려하십시오.

x => {return x * x;}; 

참고 : Func 미리 정의 된 일반적인 위임이다.

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

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

참조

  1. How can a delegate & interface be used interchangeably?
5

당신은 또한 당신의 방법에 따라 행동하는 일반적인 코드를 작성 람다 표현식의 사용을 찾을 수 있습니다.

예 : 메서드 호출에 소요 된 시간을 계산하는 일반 함수입니다. (즉,Action,

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

) 여기에 그리고 당신은 다음과 같이 람다 표현식을 사용하여 위의 방법을 호출 할 수 있습니다

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

표현은 당신이 당신의 방법에서 밖으로 반환 값을 얻을 수 있습니다

뿐만 아니라 PARAM
var timeTaken = Measure(() => returnValue = yourMethod(param, out outParam)); 
0

혁신은 유형 안전성과 투명성에 있습니다. 람다 식의 형식을 선언하지는 않더라도 유추됩니다. 코드 검색, 정적 분석, 리팩터링 도구 및 런타임 리플렉션에서 사용할 수 있습니다.

예를 들어, 해커가 숫자가 정상적으로 예상되는 문자열을 전달했기 때문에 SQL을 사용하기 전에 SQL 주입 공격을받을 수 있습니다. 이제 LINQ 람다 식을 사용합니다.이 식에서 보호됩니다.

표현 트리를 평가하기 전에 함께 결합해야하므로 순수 대리자로 LINQ API를 작성할 수 없습니다.

2016 년에 인기있는 언어의 대부분은 lambda expression이며 C#은 주류 명령형 언어 중이 진화의 개척자 중 하나였습니다.

0

이 아마도 람다 표현식을 사용하는 이유에 대한 가장 좋은 설명입니다 ->https://youtu.be/j9nj5dTo54Q 요약

, 그것은 코드의 가독성을 향상 재사용보다는 코드를 복제하고, 활용 최적화 무대 뒤에서 일어나는에 의해 오류의 가능성을 줄일 수있어 .