위임 키워드와 람다 표기법


답변:


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.