it-swarm-ko.tech

.NET Framework에서 람다와 델리게이트의 차이점은 무엇입니까?

나는이 질문에 많은 질문을 받았으며 차이점을 가장 잘 설명하는 방법에 대한 의견을 구할 것이라고 생각했습니다.

73
ScottKoon

그들은 실제로 두 가지 매우 다른 것들입니다. "델리게이트"는 실제로 메소드 또는 람다에 대한 참조를 보유하는 변수의 이름이며 람다는 영구적 인 이름이없는 메소드입니다.

람다는 몇 가지 미묘한 차이점을 제외하고는 다른 방법과 매우 유사합니다.

  1. 일반적인 방법은 "statement" 에 정의되고 영구적 인 이름에 연결되는 반면 람다는 "expression" 에 "즉석에서"정의되며 영구적 인 것은 없습니다 이름.
  2. 일부 람다는 .NET 표현식 트리와 함께 사용할 수 있지만 메서드는 사용할 수 없습니다.

델리게이트는 다음과 같이 정의됩니다.

delegate Int32 BinaryIntOp(Int32 x, Int32 y);

BinaryIntOp 유형의 변수는 서명이 동일한 한 두 개의 Int32 인수와 Int32 리턴과 같은 메소드 또는 labmda를 지정할 수 있습니다.

람다는 다음과 같이 정의 될 수 있습니다.

BinaryIntOp sumOfSquares = (a, b) => a*a + b*b;

또 다른 주목할 점은 일반적인 Func 및 Action 유형은 종종 "lambda 유형"으로 간주되지만 다른 대리인과 동일하다는 것입니다. 그들에 대한 좋은 점은 본질적으로 필요한 모든 유형의 델리게이트의 이름을 정의한다는 것입니다 (확실히 더 많은 것을 추가 할 수는 있지만 최대 4 개의 매개 변수). 따라서 다양한 대리자 유형을 사용하고 있지만 두 번 이상 사용하지 않는 경우 Func 및 Action을 사용하여 대리자 선언으로 코드를 어수선하게 만들 수 있습니다.

다음은 Func와 Action이 "람다만을위한 것이 아닌"방법을 보여줍니다.

Int32 DiffOfSquares(Int32 x, Int32 y)
{
  return x*x - y*y;
}

Func<Int32, Int32, Int32> funcPtr = DiffOfSquares;

알아야 할 또 다른 유용한 사항은 동일한 서명이지만 이름이 다른 대리자 유형 (메소드 자체가 아님)이 서로 암시 적으로 캐스트되지 않는다는 것입니다. 여기에는 Func 및 Action 델리게이트가 포함됩니다. 그러나 서명이 동일한 경우 명시 적으로 서명 할 수 있습니다.

C #에서는 람다와 델리게이트를 사용하여 유연합니다. 그러나 C #에는 "일류 함수"가 없습니다. 델리게이트 변수에 지정된 함수 이름을 사용하여 해당 함수를 나타내는 객체를 만들 수 있습니다. 그러나 실제로는 컴파일러 트릭입니다. 함수 이름과 점으로 점을 작성하여 명령문을 시작하면 (즉, 함수 자체에서 멤버 액세스를 시도하십시오) 참조 할 멤버가 없습니다. Object의 것도 아닙니다. 이것은 프로그래머가 함수에서 호출 할 수있는 확장 메소드를 추가하는 것과 같이 유용하고 잠재적으로 위험한 작업을 수행하지 못하게합니다. 당신이 할 수있는 최선의 방법은 Delegate 클래스 자체를 확장하는 것입니다.

업데이트 : 또한 익명 대리자와 메서드 및 람다의 차이점을 보여주는 Karg 's answer 도 참조하십시오.

업데이트 2 : James Hart 기술적으로 중요하지만 람다와 델리게이트는 .NET 엔터티가 아니며 (즉, CLR에는 델리게이트 나 람다 개념이 없음) 프레임 워크와 언어 구조.

86
Chris Ammerman

질문은 조금 모호합니다. 이는 답변의 넓은 차이를 설명합니다.

실제로 .NET 프레임 워크에서 람다와 델리게이트의 차이점이 무엇인지 물었습니다. 그것은 여러 가지 중 하나 일 수 있습니다. 당신은 묻는다 :

  • C # (또는 VB.NET) 언어에서 람다 식과 익명 대리자의 차이점은 무엇입니까?

  • .NET 3.5의 System.Linq.Expressions.LambdaExpression 개체와 System.Delegate 개체의 차이점은 무엇입니까?

  • 아니면 그 극단 사이 또는 주위에 뭔가?

일부 사람들은 'C # Lambda 식과 .NET System.Delegate?의 차이점은 무엇입니까?'라는 질문에 대한 답변을 제공하려고하는 것 같습니다.

.NET 프레임 워크 자체는 익명의 대리자, 람다 식 또는 클로저의 개념을 이해하지 못하며 언어 사양으로 정의 된 것입니다. C # 컴파일러가 익명 ​​메소드의 정의를 멤버 변수가있는 생성 된 클래스의 메소드로 변환하여 클로저 상태를 유지하는 방법에 대해 생각해보십시오. .NET에는 대리자에 대한 익명의 내용이 없습니다. C # 프로그래머가 익명으로 작성하는 것입니다. 델리게이트 유형에 할당 된 람다 식도 마찬가지입니다.

.NET DOES 이해하는 것은 델리게이트의 아이디어입니다. 메소드 서명을 설명하는 유형입니다. 인스턴스는 특정 객체의 특정 메소드에 대한 바운드 호출을 나타냅니다. 또는 해당 유형의 객체에 대해 호출 될 수있는 특정 유형의 특정 메소드에 대한 언 바운드 호출. 이러한 유형은 모두 System.Delegate에서 상속됩니다.

또한 .NET 3.5에는 코드 식을 설명하는 클래스가 포함 된 System.Linq.Expressions 네임 스페이스가 도입되어 특정 유형 또는 개체의 메서드에 대한 바운드 또는 언 바운드 호출을 나타낼 수도 있습니다. 그런 다음 LambdaExpression 인스턴스를 실제 대리자로 컴파일 할 수 있습니다 (표현식 구조를 기반으로하는 동적 메서드가 코드 생성되고 이에 대한 대리자 포인터가 반환 됨).

C #에서는 람다 식을 해당 형식의 변수에 할당하여 System.Expressions.Expression 형식의 인스턴스를 생성 할 수 있습니다.이 식은 런타임에 식을 구성하는 적절한 코드를 생성합니다.

물론 were C #에서 람다 식과 익명 메서드의 차이점이 무엇인지 묻는다면 결국이 모든 것이 매우 부적절합니다.이 경우 주요 차이점은 간결합니다. 매개 변수를 신경 쓰지 않고 값을 반환 할 계획이없는 경우 익명 대리자 및 유형 유추 매개 변수 및 반환 유형을 원할 때 람다.

람다 식은 식 생성을 지원합니다.

29
James Hart

한 가지 차이점은 익명 대리자가 매개 변수를 생략 할 수 있지만 람다는 정확한 서명과 일치해야한다는 것입니다. 주어진:

public delegate string TestDelegate(int i);

public void Test(TestDelegate d)
{}

다음 네 가지 방법으로 호출 할 수 있습니다 (두 번째 줄에는 매개 변수가없는 익명 대리자가 있음).

Test(delegate(int i) { return String.Empty; });
Test(delegate { return String.Empty; });
Test(i => String.Empty);
Test(D);

private string D(int i)
{
    return String.Empty;
}

매개 변수가없는 람다 식이나 매개 변수가없는 메서드를 전달할 수 없습니다. 이들은 허용되지 않습니다 :

Test(() => String.Empty); //Not allowed, lambda must match signature
Test(D2); //Not allowed, method must match signature

private string D2()
{
    return String.Empty;
}
19
Karg

델리게이트는 함수 포인터/메소드 포인터/콜백 (선택)에 해당하며 람다는 익명화 된 함수입니다. 적어도 그것이 사람들에게 말하는 것입니다.

13
Dan Shield

나는 이것에 대해 많은 경험이 없지만, 그것을 설명하는 방식은 대리자가 모든 함수를 감싸는 래퍼이며 람다 식 자체는 익명 함수라는 것입니다.

3
chessguy

델리게이트는 항상 기본적으로 함수 포인터입니다. 람다는 델리게이트로 전환 될 수 있지만 LINQ 표현식 트리로 전환 될 수도 있습니다. 예를 들어

Func<int, int> f = x => x + 1;
Expression<Func<int, int>> exprTree = x => x + 1;

첫 번째 줄은 델리게이트를 생성하고 두 번째 줄은 표현식 트리를 생성합니다.

3
Curt Hagenlocher

대리자는 특정 매개 변수 목록과 반환 유형이있는 메서드에 대한 참조입니다. 객체를 포함하거나 포함하지 않을 수 있습니다.

람다 표현은 익명 함수의 한 형태입니다.

2
Peter Ritchie

람다는 대의원에서 단순히 구문 설탕입니다. 컴파일러는 람다를 델리게이트로 변환합니다.

이것도 마찬가지입니다.

Delegate delegate = x => "hi!";
Delegate delegate = delegate(object x) { return "hi";};
2
Gilligan

델리게이트는 함수 서명입니다. 같은

delegate string MyDelegate(int param1);

대리인은 본문을 구현하지 않습니다.

람다는 대리자의 서명과 일치하는 함수 호출입니다. 위 대리인의 경우 다음 중 하나를 사용할 수 있습니다.

(int i) => i.ToString();
(int i) => "ignored i";
(int i) => "Step " + i.ToString() + " of 10";

그러나 Delegate 유형의 이름이 잘못되었습니다. Delegate 유형의 객체를 생성하면 실제로 람다, 정적 메소드 또는 클래스 메소드 등 함수를 보유 할 수있는 변수가 생성됩니다.

2
Steve Cooper

이 질문이 "람다와 익명 델리게이트의 차이점은 무엇입니까?"라는 것이 분명했습니다. 여기에있는 모든 답변 중 단 한 사람만이 옳았습니다. 주된 차이점은 람다는 표현 트리와 대리자를 만드는 데 사용될 수 있다는 것입니다.

MSDN에서 자세한 내용을 읽을 수 있습니다. http://msdn.Microsoft.com/en-us/library/bb397687.aspx

2
Philip Beber

델리게이트는 함수 포인터의 큐이며, 델리게이트를 호출하면 여러 메소드를 호출 할 수 있습니다. 람다는 본질적으로 익명 메소드 선언으로, 사용되는 컨텍스트에 따라 컴파일러가 다르게 해석 할 수 있습니다.

람다 식을 대리자로 캐스트하거나 특정 대리자 형식을 기대하는 메서드에 매개 변수로 전달하면 컴파일러에서 람다 식을 가리키는 대리자를 얻을 수 있습니다. LINQ 문 내에서이를 사용하면 람다는 컴파일러에서 단순히 대리자가 아닌 식 트리로 변환됩니다.

차이점은 람다는 다른 표현식 내부에서 메소드를 정의하는 간결한 방법이며 델리게이트는 실제 객체 유형이라는 것입니다.

1
justin.m.chase

대의원은 실제로 함수에 대한 구조적 타이핑입니다. 인터페이스 또는 추상 클래스를 구현하는 익명 클래스를 명목 타이핑하고 구현하는 것과 동일한 작업을 수행 할 수 있지만 함수가 하나만 필요한 경우 많은 코드가됩니다.

람다는 1930 년대 알론조 교회의 람다 미적분학이라는 아이디어에서 비롯되었습니다. 익명의 함수 작성 방법입니다. 함수 작성에 특히 유용합니다.

일부 사람들은 람다는 대의원에게 구문 설탕이라고 말하지만, 대의원은 사람들을 C #으로 람다로 풀어주는 다리라고 말합니다.

1
Steve g

여기 내 절름발이 블로그에 잠시 올려 놓은 예가 있습니다. 작업자 스레드에서 레이블을 업데이트하려고한다고 가정하십시오. 델리게이트, 아논 델리게이트 및 2 가지 유형의 람다를 사용하여 레이블을 1에서 50으로 업데이트하는 방법에 대한 4 가지 예가 있습니다.

 private void button2_Click(object sender, EventArgs e) 
     { 
         BackgroundWorker worker = new BackgroundWorker(); 
         worker.DoWork += new DoWorkEventHandler(worker_DoWork); 
         worker.RunWorkerAsync(); 
     } 

     private delegate void UpdateProgDelegate(int count); 
     private void UpdateText(int count) 
     { 
         if (this.lblTest.InvokeRequired) 
         { 
             UpdateProgDelegate updateCallBack = new UpdateProgDelegate(UpdateText); 
             this.Invoke(updateCallBack, new object[] { count }); 
         } 
         else 
         { 
             lblTest.Text = count.ToString(); 
         } 
     } 

     void worker_DoWork(object sender, DoWorkEventArgs e) 
     {   
         /* Old Skool delegate usage.  See above for delegate and method definitions */ 
         for (int i = 0; i < 50; i++) 
         { 
             UpdateText(i); 
             Thread.Sleep(50); 
         } 

         // Anonymous Method 
         for (int i = 0; i < 50; i++) 
         { 
             lblTest.Invoke((MethodInvoker)(delegate() 
             { 
                 lblTest.Text = i.ToString(); 
             })); 
             Thread.Sleep(50); 
         } 

         /* Lambda using the new Func delegate. This lets us take in an int and 
          * return a string.  The last parameter is the return type. so 
          * So Func<int, string, double> would take in an int and a string 
          * and return a double.  count is our int parameter.*/ 
         Func<int, string> UpdateProgress = (count) => lblTest.Text = count.ToString(); 
         for (int i = 0; i < 50; i++) 
         { 
             lblTest.Invoke(UpdateProgress, i); 
             Thread.Sleep(50); 
         } 

         /* Finally we have a totally inline Lambda using the Action delegate 
          * Action is more or less the same as Func but it returns void. We could 
          * use it with parameters if we wanted to like this: 
          * Action<string> UpdateProgress = (count) => lblT…*/ 
         for (int i = 0; i < 50; i++) 
         { 
             lblTest.Invoke((Action)(() => lblTest.Text = i.ToString())); 
             Thread.Sleep(50); 
         } 
     }
0
Echostorm

여기 몇 가지 기본 사항이 있습니다. "Delegate"는 실제로 메소드 또는 람다에 대한 참조를 보유한 변수의 이름입니다.

이것은 익명의 방법입니다-

(string testString) => { Console.WriteLine(testString); };

익명 메소드에는 이름이 없으므로 이러한 메소드 또는 표현식을 모두 지정할 수있는 대리자가 필요합니다. 예를 들어.

delegate void PrintTestString(string testString); // declare a delegate

PrintTestString print = (string testString) => { Console.WriteLine(testString); }; 
print();

람다 식과 동일합니다. 보통 우리는 그들을 사용하기 위해 대리인이 필요합니다

s => s.Age > someValue && s.Age < someValue    // will return true/false

Func 델리게이트를 사용하여이 표현식을 사용할 수 있습니다.

Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ;

bool result = checkStudentAge ( Student Object);
0
Yogesh Prajapati

람다는 대리자의 단순화 된 버전입니다. 익명 대리자와 같은 closure 의 속성 중 일부는 있지만 암시 적 타이핑을 사용할 수도 있습니다. 이와 같은 람다 :

something.Sort((x, y) => return x.CompareTo(y));

대리인으로 할 수있는 것보다 훨씬 간결합니다.

something.Sort(sortMethod);
...

private int sortMethod(SomeType one, SomeType two)
{
    one.CompareTo(two)
}
0
Michael Meadows