위임 키워드와 람다 표기법


답변:


140

짧은 대답 : 아니오.

관련이 없을 수있는 더 긴 답변 :

  • 람다를 델리게이트 유형 ( Func또는 과 같은 Action)에 할당하면 익명의 델리게이트가 나타납니다.
  • 람다를 표현식 유형에 할당하면 익명 대리자 대신 표현식 트리가 나타납니다. 그런 다음 식 트리를 익명 대리자로 컴파일 할 수 있습니다.

편집 : 여기 Expressions에 대한 링크가 있습니다.

  • System.Linq.Expression.Expression (TDelegate) (여기서 시작).
  • 대리자가있는 Linq 인 메모리 (예 : System.Func)는 System.Linq.Enumerable을 사용합니다 . 표현식이있는 Linq to SQL (및 기타)은 System.Linq.Queryable을 사용합니다 . 해당 메소드의 매개 변수를 확인하십시오.
  • ScottGu 의 설명 . 간단히 말해서 Linq 인 메모리는 쿼리를 해결하기위한 익명의 메소드를 생성합니다. Linq to SQL은 쿼리를 나타내는 식 트리를 생성 한 다음 해당 트리를 T-SQL로 변환합니다. Linq to Entities는 쿼리를 나타내는 표현식 트리를 생성 한 다음 해당 트리를 플랫폼에 적합한 SQL로 변환합니다.

3
식 타입? 이것은 나에게 새로운 영토처럼 들린다. C #에서 식 유형 및 식 트리 사용에 대한 자세한 내용은 어디에서 찾을 수 있습니까?
— MojoFilter

2
더 긴 대답-다른 대의원 유형으로 전환 할 수있는 근거가 있습니다 :)
— Jon Skeet

람다는 표현식 람다 인 경우 표현식 유형에만 지정할 수 있습니다.
— Micha Wiedenmann

125

나는 에이미의 대답이 마음에 들지만, 나는 농민이라고 생각했다. 두 표현식이 제안하는 - 질문은 "이 컴파일되면"라고 했다 컴파일. 어떻게 컴파일 할 수는 있지만 하나는 대리자로 변환되고 다른 하나는 식 트리로 변환됩니까? 까다로운 방법입니다. 익명 메소드의 다른 기능을 사용해야합니다. 람다 식에서 공유하지 않는 유일한 것입니다. 매개 변수 목록 을 지정하지 않고 익명 메소드를 지정하면 void를 리턴하고 out매개 변수 없이 모든 델리게이트 유형과 호환됩니다 . 이러한 지식으로 무장하지만 표현이 완전히 명확 해 지도록 두 개의 과부하를 구성 할 수 있어야합니다.

그러나 재난이 닥쳤습니다! 적어도 C # 3.0에서는 블록 본문이있는 람다 식을 식으로 변환 할 수 없으며 본문에 람다 식을 반환 값으로 사용하더라도 할당 할 수 없습니다. 이는 C # 4.0 및 .NET 4.0에서 변경 될 수 있으며,이를 통해 표현식 트리에서 더 많은 것을 표현할 수 있습니다. 다시 말해, MojoFilter가 제공 한 예제를 통해 두 개는 거의 항상 같은 것으로 변환됩니다. (분 후에 더 자세한 내용)

바디를 약간 변경하면 델리게이트 매개 변수 트릭을 사용할 수 있습니다.

using System;
using System.Linq.Expressions;

public class Test
{
    static void Main()
    {
        int x = 0;
        Foo( () => x );
        Foo( delegate { return x; } );
    }

    static void Foo(Func<int, int> action)
    {
        Console.WriteLine("I suspect the anonymous method...");
    }

    static void Foo(Expression<Func<int>> func)
    {
        Console.WriteLine("I suspect the lambda expression...");
    }
}

하지만 기다려! 충분히 교활한 경우 식 트리를 사용하지 않아도 둘을 구별 할 수 있습니다. 아래 예는 과부하 해결 규칙과 익명 대리자 일치 트릭을 사용합니다.

using System;
using System.Linq.Expressions;

public class Base
{
    public void Foo(Action action)
    {
        Console.WriteLine("I suspect the lambda expression...");
    }
}

public class Derived : Base
{
    public void Foo(Action<int> action)
    {
        Console.WriteLine("I suspect the anonymous method...");
    }
}

class Test
{
    static void Main()
    {
        Derived d = new Derived();
        int x = 0;
        d.Foo( () => { x = 0; } );
        d.Foo( delegate { x = 0; } );
    }
}

아야. 기본 클래스에서 상속 된 메서드를 오버로드 할 때마다 작은 새끼 고양이가 울기 시작합니다.


9
팝콘을 꺼내서 모든 내용을 읽었습니다. 그것은 내가 얼굴을 똑바로 쳐다 보더라도 결코 생각하지 않을 것이라는 점입니다.
— MojoFilter

27
나는 이것의 일부를 알고 있었지만, 당신에게 그것을 인간에게 전하는 능력에 대해 축하해야한다.
— Amy B

1
.NET 4.0 (CTP 기반)의 변경에 관심이있는 사람은 marcgravell.blogspot.com/2008/11/future-expressions.html을 참조하십시오 . C # 4.0은 내가 알 수있는 한 아직 새로운 것을하지 않습니다.
— Marc Gravell

4
존, 넌 흔들어 에릭, 진정한 Skeet fanboi가 되려면, 스택 오버플로 rss에 가입해야합니다. stackoverflow.com/users/22656 을 피드 리더에 붙이기 만하면 됩니다.
— Paul Batum

3
@RoyiNamir : 매개 변수 목록없이 익명 메소드를 사용하는 경우 리턴 유형이 호환되는 한 비 참조 / 출력 매개 변수 가 있는 모든 델리게이트 유형과 호환됩니다. 기본적으로 "파라미터에 신경 쓰지 않습니다"라고 말합니다. 참고 delegate { ... }인 하지 와 같은 delegate() { ... }후자는 매개 변수가 대리자 형식 만 호환됩니다 -.
— Jon Skeet

2

위의 두 예에서는 차이가 없습니다.

표현식:

() => { x = 0 }

문 본문이있는 Lambda 식이므로 식 트리로 컴파일 할 수 없습니다. 실제로 0 뒤에 세미콜론이 필요하기 때문에 컴파일조차하지 않습니다.

() => { x = 0; } // Lambda statement body
() => x = 0      // Lambda expression body, could be an expression tree. 

6
분명히 그것은 "하나는 컴파일 할 것이고 다른 하나는 그렇지 않을 것"의 차이가 있다는 것을 의미합니다.
— Jon Skeet

2

에이미 B가 맞습니다. 식 트리를 사용하면 이점이있을 수 있습니다. LINQ to SQL은 표현식 트리를 검사하여 SQL로 변환합니다.

라다 및 표현 트리를 사용하여 트릭을 재생하여 리팩토링이 안전한 방식으로 클래스 멤버의 이름을 프레임 워크에 효과적으로 전달할 수 있습니다. Moq 가 이에 대한 예입니다.


-1

차이가 있습니다

예:

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(delegate
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});   

그리고 나는 lambda로 대체합니다 : (오류)

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(()=>
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});

메소드 매개 변수 서명이 일치하지 않아서 잘못 ~ 람다는 실패했습니다.
— Jack Wang

-1

여기 몇 가지 기본 사항이 있습니다.

이것은 익명의 방법입니다

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