[C#] Lambda의 원리와 캡처 시 임시 클래스 생성에 대해서

Date:     Updated:

카테고리:

태그:

Lambda의 원리와 캡처 시 임시 클래스 생성에 대해서 공부하고 정리한 글입니다.

람다식의 원리

  • 람다식을 사용하면 컴파일러가 임시 클래스가 하나 생성시켜준다
    • 2023-05-28-csharp-11-19-30-49.png
  • 람다식 안의 코드는 임시 클래스의 멤버 함수로 변하게 된다
    • 2023-05-28-csharp-11-19-34-47.png
  • 캡처가 이루어지는 경우 임시 클래스의 멤버로 가지게 된다
    • 비정적 변수를 캡처하여 임시 클래스가 생성된 경우 람다식이 있는 Scope를 진입할 때마다 임시 클래스를 동적 할당하게 된다
  • 람다식을 사용하는 경우 delegate 객체를 동적 할당하게 된다
  • 람다식을 호출하면 임시 클래스의 멤버 함수가 호출된다
    • 2023-05-28-csharp-11-19-55-48.png

각종 예시

  • 밑에 예시를 보면서 캡처방식마다 어떻게 임시 클래스가 생성되는지 확인하자

케이스 1 : 하나의 람다식이 존재하는 경우

public class Name
{
    private string instanceName;

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

    public void DisplayToWindow()
    {
        Console.WriteLine(this.instanceName);
    }
}

public class Program
{
    static void Main(string[] args)
    {
        Name testName = new Name("Koani");
        Action showMethod = () => testName.DisplayToWindow();
        showMethod();
    }
}
  • 2023-05-28-csharp-11-14-34-01.png
  • 람다식의 코드를 가지는 임시 클래스 하나가 생성되게 된다

케이스 2 : 여러 람다식이 존재하는 경우

static void Main(string[] args)
{
    int testName = 5;
    Action showMethod = () => { ++testName; Console.WriteLine(testName); };
    Action showMethod2 = () => { Console.WriteLine(testName); };
    Action showMethod3 = () => { Console.WriteLine(testName); };
    Action showMethod4 = () => { Console.WriteLine(testName); };
    Action showMethod5 = () => { Console.WriteLine(testName); };
    Action showMethod6 = () => { Console.WriteLine(testName); };
    Action showMethod7 = () => { Console.WriteLine(testName); };
    Action showMethod8 = () => { Console.WriteLine(testName); };
    Action showMethod9 = () => { Console.WriteLine(testName); };
    showMethod();
    showMethod2();
}
  • 2023-05-28-csharp-11-14-35-10.png
  • 여러 람다식마다 함수가 생성된다

케이스 3 : 여러 람다식이 다른 비정적 변수를 캡처하는 경우

static void Main(string[] args)
{
    int i = 256;
    string s = "string";
    double d = 135.513;
    Action showMethod1 = () => { Console.WriteLine(i); };
    Action showMethod2 = () => { Console.WriteLine(s); Console.WriteLine(++i); };
    Action showMethod3 = () => { Console.WriteLine(d += 123.456); Console.WriteLine(s += "add"); Console.WriteLine(++i); };
    showMethod1();
    showMethod2();
    showMethod3();
    showMethod3();
    showMethod2();
    showMethod1();
}
  • 2023-05-28-csharp-11-14-35-57.png
  • 다른 비정적 변수를 캡처한다고 해서 임시 클래스가 나뉘어지지 않는다

케이스 4 : 비정적 변수를 캡처하고 정적 변수를 사용하는 경우

public class TestClass
{
    int i = 256;
    double d = 135.513;

    public void Test()
    {
        Action showMethod1 = () => { Console.WriteLine(++Program.staticInt); };
        Action showMethod2 = () => { Console.WriteLine(showMethod1); Console.WriteLine(++i); };
        Action showMethod3 = () => { Console.WriteLine(d += 123.456); Console.WriteLine(showMethod2); Console.WriteLine(showMethod2); };
        Action showMethod4 = () => { Console.WriteLine(TestClass222.staticDouble += 12.45); };
        showMethod1();
        showMethod2();
        showMethod3();
        showMethod4();
    }
}

public class TestClass222
{
    public static double staticDouble = 123.456;
}

public class Program
{
    public static int staticInt = 132;
    static void Main(string[] args)
    {
        TestClass test = new TestClass();
        test.Test();
    }
}
  • 2023-05-28-csharp-11-14-37-14.png
  • 정적 변수와 같이 같은 Scope(범위)에 없는 경우 따로 임시 클래스가 만들어 진다
    • 근데 케이스 5 는 정적 변수를 사용했음에도 클래스가 나뉘어 지지 않는다

케이스 5 : 하나의 람다식에서 비정적 변수를 캡처하고 정적 변수를 사용하는 경우

public class TestClass
{
    int i = 256;
    double d = 135.513;

    public void Test()
    {
        Action showMethod1 = () => { Console.WriteLine(d += 123.456); Console.WriteLine(++Program.staticInt); };
        Action showMethod2 = () => { Console.WriteLine(showMethod1); Console.WriteLine(++i); };
        Action showMethod3 = () => { Console.WriteLine(d += 123.456); Console.WriteLine(showMethod2); Console.WriteLine(showMethod2); };
        Action showMethod4 = () => { Console.WriteLine(TestClass222.staticDouble += 12.45); Console.WriteLine(d += 123.456); };
        showMethod1();
        showMethod2();
        showMethod3();
        showMethod4();
    }
}

public class TestClass222
{
    public static double staticDouble = 123.456;
}

public class Program
{
    public static int staticInt = 132;
    static void Main(string[] args)
    {
        TestClass test = new TestClass();
        test.Test();
    }
}
  • 2023-05-28-csharp-11-14-38-03.png
  • 정적 변수만 사용되는 경우 정적 클래스가 따로 만들어지고 만약 비정적 변수를 같이 캡처하는 경우 하나의 임시 클래스로 합쳐지는 것으로 보인다

케이스 6 : 다른 클래스 같은 동작의 람다 함수인 경우 (캡처 X)

public class TestClass
{
    public void Test()
    {
        Action showMethod1 = () => { Console.WriteLine(); };
        showMethod1();
    }
}

public class Program
{
    static void Main(string[] args)
    {
        TestClass test = new TestClass();
        test.Test();

        Action showMethod1 = () => { Console.WriteLine(); };
        showMethod1();
    }
}
  • 2023-05-28-csharp-11-14-39-00.png
  • 같은 동작의 함수라고 해서 같은 임시 클래스를 사용하지는 않는다 (2개의 임시 클래스가 생성됨)

케이스 7 : 다른 클래스 같은 동작의 람다 함수인 경우 (비정적 변수 캡처, 정적 변수 사용)

public class TestClass
{
    int i = 256;
    double d = 135.513;

    public void Test()
    {
        Action showMethod1 = () => { Console.WriteLine(++Program.staticInt); };
        Action showMethod2 = () => { Console.WriteLine(showMethod1); Console.WriteLine(++i); };
        Action showMethod3 = () => { Console.WriteLine(d += 123.456); Console.WriteLine(showMethod2); Console.WriteLine(showMethod2); };
        Action showMethod4 = () => { Console.WriteLine(TestClass222.staticDouble += 12.45); };
        showMethod1();
        showMethod2();
        showMethod3();
        showMethod4();
    }
}

public class TestClass222
{
    public static double staticDouble = 123.456;
}

public class Program
{
    public static int staticInt = 132;

    static void Main(string[] args)
    {
        TestClass test = new TestClass();
        test.Test();

        int i = 256;
        double d = 135.513;

        Action showMethod1 = () => { Console.WriteLine(++staticInt); };
        Action showMethod2 = () => { Console.WriteLine(showMethod1); Console.WriteLine(++i); };
        Action showMethod3 = () => { Console.WriteLine(d += 123.456); Console.WriteLine(showMethod2); Console.WriteLine(showMethod2); };
        Action showMethod4 = () => { Console.WriteLine(TestClass222.staticDouble += 12.45); };
        showMethod1();
        showMethod2();
        showMethod3();
        showMethod4();
    }
}
  • 2023-05-28-csharp-11-14-40-22.png
  • 코드가 중복이 되더라도 서로 Scope가 다르면 임시 클래스가 따로 생긴다

참조

관련 코드



💻 열심히 공부해서 작성 중이니 오류나 틀린 부분이 있을 경우 
  언제든지 댓글 혹은 메일로 알려주시면 감사하겠습니다! 😸

맨 위로 이동하기

CSharp 카테고리 내 다른 글 보러가기

댓글 남기기