Nice programing

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

nicepro 2020. 10. 18. 19:33
반응형

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


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


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

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

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

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

delegate Int32 BinaryIntOp(Int32 x, Int32 y);

BinaryIntOp 유형의 변수는 서명이 동일한 경우 메서드 또는 labmda를 할당 할 수 있습니다. 두 개의 Int32 인수와 하나의 Int32 반환.

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

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

주목해야 할 또 다른 점은 일반 Func 및 Action 유형이 종종 "람다 유형"으로 간주되지만 다른 대리자와 동일하다는 것입니다. 이것의 좋은 점은 기본적으로 필요한 모든 유형의 델리게이트에 대한 이름을 정의한다는 것입니다 (최대 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의 답변 도 참조하십시오 .

업데이트 2 : James Hart 는 매우 기술적이지만 중요하지만 람다와 델리게이트는 .NET 엔터티가 아니라 (즉, CLR에는 델리게이트 또는 람다의 개념이 없음) 오히려 프레임 워크 및 언어 구성이라는 점에 유의합니다.


질문은 약간 모호하며, 이는 귀하가받는 답변의 광범위한 불일치를 설명합니다.

실제로 .NET 프레임 워크에서 람다와 대리자의 차이점이 무엇인지 물었습니다. 여러 가지 중 하나 일 수 있습니다. 당신은 묻고 있습니까?

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

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

  • 아니면 그 극단 사이 또는 그 주변 어딘가에 있습니까?

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

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

무엇 .NET 않는이 방법 서명을 설명하는 유형 중 하나에 대해 호출 할 수있는 특정 유형의 특정 방법에 특정 개체 또는 언 바운드 통화에 대한 구체적인 방법에 대한 호출을 바인딩 표현한다 인스턴스있는 -을 이해하는 것은 대표의 생각이다 해당 유형의 모든 객체, 여기서 상기 방법은 상기 서명을 준수합니다. 이러한 유형은 모두 System.Delegate에서 상속됩니다.

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

C #에서는 해당 유형의 변수에 람다 식을 할당하여 System.Expressions.Expression 유형의 인스턴스를 생성 할 수 있습니다. 그러면 런타임에 식을 생성하는 데 적합한 코드가 생성됩니다.

물론, 당신이 경우 차이가 람다 표현식과 C #의 익명 메소드 사이에 무엇을 물어 ', 결국, 모든이 거의 irelevant이며,이 경우 주 차이는 익명의 대의원을 향해 몸을 숙 당신이 돈 때하는 간결하다 매개 변수에 신경을 쓰지 않고 값을 반환 할 계획을 세우지 않고 유형 추론 매개 변수 및 반환 유형을 원할 때 람다를 사용합니다.

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


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

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

델리게이트는 함수 포인터 / 메소드 포인터 / 콜백 (선택)과 동일하며 람다는 매우 단순화 된 익명 함수입니다. 적어도 나는 사람들에게 그렇게 말합니다.


나는 이것에 대해 많은 경험이 없지만 델리게이트는 모든 함수를 감싸는 래퍼이고 람다 식 자체는 익명 함수라는 것입니다.


대리자는 항상 기본적으로 함수 포인터입니다. 람다는 대리자로 바뀔 수 있지만 LINQ 식 트리로도 바뀔 수도 있습니다. 예를 들어

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

첫 번째 줄은 대리자를 생성하고 두 번째 줄은 식 트리를 생성합니다.


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

이것들은 똑같습니다.

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

델리게이트는 함수 서명입니다. 뭔가

delegate string MyDelegate(int param1);

대리자는 본문을 구현하지 않습니다.

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

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

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


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

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


"람다와 익명 대리자 의 차이점은 무엇 입니까?" 라는 질문이 의도 된 것이 분명합니다. 여기에있는 모든 답변 중에서 단 한 사람 만 올바르게 답했습니다. 주요 차이점은 람다를 사용하여 표현 트리와 델리게이트를 생성 할 수 있다는 것입니다.

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


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

Lambda는 1930 년대 알론조 교회의 람다 미적분 아이디어에서 비롯되었습니다. 함수를 만드는 익명의 방법입니다. 기능을 구성하는 데 특히 유용합니다.

그래서 어떤 사람들은 람다가 델리게이트를위한 통사론 적 설탕이라고 말할 수 있지만, 델리게이트는 사람들을 C #에서 람다로 편하게 만드는 다리라고 말할 수 있습니다.


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

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

차이점은 람다는 다른 식 내부에 메서드를 정의하는 간결한 방법 인 반면 대리자는 실제 개체 형식이라는 것입니다.


Lambda는 단순화 된 대리자 버전입니다. 익명 델리게이트와 같은 클로저 의 속성 중 일부를 가지고 있지만 묵시적 타이핑을 사용할 수도 있습니다. 다음과 같은 람다 :

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

델리게이트로 할 수있는 것보다 훨씬 간결합니다.

something.Sort(sortMethod);
...

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

여기 내가 절름발이 블로그에 잠시 올린 예가 있습니다. 작업자 스레드에서 레이블을 업데이트하고 싶다고 가정 해보십시오. 델리게이트, anon 델리게이트 및 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); 
         } 
     }

귀하의 질문은 .NET이 아닌 .NET이 아닌 c #에 관한 것으로 가정합니다. .NET은 혼자가 아니기 때문에-즉, c #없이-대리자와 람다 식을 이해하기 때문입니다.

A (normal, in opposition to so called generic delegates, cf later) delegate should be seen as a kind of c++ typedef of a function pointer type, for instance in c++ :

R (*thefunctionpointer) ( T ) ;

typedef's the type thefunctionpointer which is the type of pointers to a function taking an object of type T and returning an object of type R. You would use it like this :

thefunctionpointer = &thefunction ;
R r = (*thefunctionpointer) ( t ) ; // where t is of type T

where thefunction would be a function taking a T and returning an R.

In c# you would go for

delegate R thedelegate( T t ) ; // and yes, here the identifier t is needed

and you would use it like this :

thedelegate thedel = thefunction ;
R r = thedel ( t ) ; // where t is of type T

where thefunction would be a function taking a T and returning an R. This is for delegates, so called normal delegates.

Now, you also have generic delegates in c#, which are delegates that are generic, i.e. that are "templated" so to speak, using thereby a c++ expression. They are defined like this :

public delegate TResult Func<in T, out TResult>(T arg);

And you can used them like this :

Func<double, double> thefunctor = thefunction2; // call it a functor because it is
                                                // really as a functor that you should
                                                // "see" it
double y = thefunctor(2.0);

where thefunction2 is a function taking as argument and returning a double.

Now imagine that instead of thefunction2 I would like to use a "function" that is nowhere defined for now, by a statement, and that I will never use later. Then c# allows us to use the expression of this function. By expression I mean the "mathematical" (or functional, to stick to programs) expression of it, for instance : to a double x I will associate the double x*x. In maths you write this using the "\mapsto" latex symbol. In c# the functional notation has been borrowed : =>. For instance :

Func<double, double> thefunctor = ( (double x) => x * x ); // outer brackets are not
                                                           // mandatory

(double x) => x * x is an expression. It is not a type, whereas delegates (generic or not) are.

Morality ? At end, what is a delegate (resp. generic delegate), if not a function pointer type (resp. wrapped+smart+generic function pointer type), huh ? Something else ! See this and that.


Some basic here. "Delegate" is actually the name for a variable that holds a reference to a method or a lambda

This is a anonymous method -

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

As anonymous method do not have any name we need a delegate in which we can assign both of these method or expression. For Ex.

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

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

Same with the lambda expression. Usually we need delegate to use them

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

We can use a func delegate to use this expression.

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

bool result = checkStudentAge ( Student Object);

Well, the really oversimplified version is that a lambda is just shorthand for an anonymous function. A delegate can do a lot more than just anonymous functions: things like events, asynchronous calls, and multiple method chains.

참고URL : https://stackoverflow.com/questions/73227/what-is-the-difference-between-lambdas-and-delegates-in-the-net-framework

반응형