lamda

1. 람다 식


람다식은 무명 메소드를 단순한 계산식으로 표현한것이다.
람다 식은 람다 연산자 => 왼쪽에 입력 매개 변수를 지정하고 오른 쪽에 식이나 문 블록을 삽입한다.

(a, b) => a + b

델리게이트를 사용한 무명 메소드를 람다식으로 표현하면 다음과 같다.
람다식은 매개변수 a, b의 타입도 생략 할수 있다.

delegate int CalcDelegate(int a, int b);
CalcDelegate A;

//무명 메소드
A = delegate( int a, int b)
      {  
            return a + b; 
       };




--->

delegate int CalcDelegate(int a, int b);
CalcDelegate A;

//람다식
A = ( int a, int b) => a+b;

//동일한 람다식
A = (a, b) => a+b;

사용 예제를 보자.

    class Test
    {
        delegate int CalcDelegate(int a, int b);
        public Test()
        {
            CalcDelegate add = (a, b) => a + b;
            Console.WriteLine("add={0}", add(3, 7));
        }
    }

2.  람다 문


중괄호 둘러싸고 함수처럼 사용 할수 있는 것을 람다 문이라고 한다.

        delegate int CalcDelegate(int a, int b);
        public Test()
        {
            CalcDelegate add = (a, b) =>
                {
                    int sum = a + b;
                    Console.WriteLine("add={0}", sum);
                    return sum;
                };

            add(3, 7);
        }

3. 비동기 람다

??? 아직 미작성.......

4. Func, Action 델리게이트


반환값이 있는 Func 델리게이트와 반환값이 없는 Action 델리게이트가 만들어져 있다.
무명 메소드 뿐만 아니라 일반 메소드도 사용할수 있다.

리턴값이 없는 Action 예제를 보자.

        void Display()
        {
            Console.WriteLine("Display");
        }

        public Test()
        {
            Action a1 = new Action(Display);
            a1();

            Action a11 = this.Display;
            a11();

            Action<string> a2 = (str) => Console.WriteLine("Action<string> {0}", str);
            a2("test");
        }

a1은 Action 대리자로 일반 함수인 Display( ) 함수를 호출하고 있다.
a11도 a1과 같 Action 대리자로 일반 함수인 Display( ) 함수를 호출하고 있다.

a2는 Action<T> 대리자로 무명 메소드를 사용하고 있다.
T1부터 T16까지 16개의 매개변수를 지원한다.

리턴값이 있는 Func 예제를 보자.

        bool Display()
        {
            Console.WriteLine("Display");
            return true;
        }

        public Test()
        {
            Func<bool> a1 = this.Display;
            a1();

            Func<string, float> a2 = (str) => 0.5f;
            float ret = a2("test");
            Console.WriteLine("a2 = {0}", ret);
        }

a1은 Func<TResult> 대리자로 일반 함수인 Display를 함수를 호출하고 있다.

a2는 Func<T, TResult> 대리자로 무명 메소드를 사용하고 있다.
T1부터 T16까지 16개의 매개변수를 지원한다.

Func<TResult> Delegate의 실제 구현은 다음과 같다.

public delegate TResult Func<out TResult>();

Func<TResult> Delegate는 매개변수가 없고 리턴값만 있다.
람다문으로 표현 할때는 일반 함수처럼 return을 붙이지만 람다식으로 할때는 return을 안 붙여도 된다.

using System;

public void Test()
{
    Func<int> f;
#if false            
    f = () =>
    {
        return (2 + 3);
    };
#else            
    f = () => 2+3;
#endif
    Console.WriteLine(f());
}

5. 람다 변수 캡쳐

람다문(식)에 사용되는 변수는 컴파일시 별도로 만들어 준다. 주의점을 살펴보자.

using System;
using System.Windows.Forms;

public class Name
{
    private string instanceName;

    public Name(string name)
    {
        this.instanceName = name;
    }

    public void DisplayToWindow()
    {
        MessageBox.Show(this.instanceName);
    }
}

public class LambdaExpression
{
    public static void Main()
    {
        Name testName = new Name("Koani");
        Action showMethod = () => testName.DisplayToWindow();
        showMethod();
    }
}

Action showMethod = () => testName.DisplayToWindow();

위의 람다문은 컴파일시에 다음과 같이 생성된다.

public class [임시클래스]
{
    Name _name;

    public void _f()
    {
        _name.DisplayToWindow(); // showMethod에 넣었던 Lambda 메서드 body
    }
}

원래의 소스를 다음과 같이 바꾼다.

public static void Main()
{
    [임시클래스] _var = new [임시클래스]();

    _var._name = new Name("Koani");
    Action showMethod = _var._f;

    showMethod();
}

람다의 변수 캡쳐에 대한 주의 사항으로 다음 예제를 보자.

//http://stackoverflow.com/questions/451779/how-to-tell-a-lambda-function-to-capture-a-copy-instead-of-a-reference-in-c

using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        List<Action> actions = new List<Action>();

        for (int i = 0; i < 10; ++i)
        {
            actions.Add(() => Console.WriteLine(i));
        }

        foreach (Action a in actions)
        {
            a();
        }

        // 기대하던 출력: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
        // 실제 출력:    10, 10, 10, 10, 10, 10, 10, 10, 10, 10
    }
}

임시 클래스가 만들어지고 마지막 값 10을 공유하게 된다.

//http://stackoverflow.com/questions/451779/how-to-tell-a-lambda-function-to-capture-a-copy-instead-of-a-reference-in-c

using System;
using System.Collections.Generic;

public class [임시클래스]
{
    public int _i;
    public void _f()
    {
        Console.WriteLine(_i);
    }
}

class Program
{
    static void Main(string[] args)
    {
        List<Action> actions = new List<Action>();

        [임시클래스] _var = new [임시클래스]();

        for (_var._i = 0; _var._i < 10; ++_var._i)
        {
            actions.Add(_var._f);
        }

        foreach (Action a in actions)
        {
            a();
        }
    }
}

1, 2, 3, 4, 5, 6, 7, 8, 9, 10이 정상적으로 출력 되게 할려면 다음과 같이 한다.
for 구문 영역안에 변수를 하나 선언해서 값을 전달한다.

using System;
using System.Collections.Generic;
class Program
{
    static void Main(string[] args)
    {
        List<Action> actions = new List<Action>();

        for (int i = 0; i < 10; ++i)
        {
            int v = i;
            actions.Add(() => Console.WriteLine(v));
        }

        foreach (Action a in actions)
        {
            a();
        }
    }
}

컴파일시에 생성된 코드는 다음과 같다.
for 구문 안에서 변수를 만들었기 때문에 for 안에서 new가 생성되었다.

//http://stackoverflow.com/questions/451779/how-to-tell-a-lambda-function-to-capture-a-copy-instead-of-a-reference-in-c

using System;
using System.Collections.Generic;

public class [임시클래스]
{
    public int _v;
    public void _f()
    {
        Console.WriteLine(_i);
    }
}

class Program
{
    static void Main(string[] args)
    {
        List<Action> actions = new List<Action>();

        for (int i = 0; i < 10; ++i)
        {
            [임시클래스] _var = new [임시클래스]();
            _var._v = i;
            actions.Add(_var._f);
        }

        foreach (Action a in actions)
        {
            a();
        }
    }
}


참조)
http://mrw0119.tistory.com/22
https://msdn.microsoft.com/ko-kr/library/bb397687.aspx
http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&detail=1&wid=10817