람다식

개발조하·2023년 11월 10일
0

C#

목록 보기
8/11
post-thumbnail

1. 람다식이란?

람다식(Lamda Expression) 은 수학자 알론조 처치가 분명하고 간결한 방법으로 함수를 묘사하기 위해 고안한 람다 계산법이 프로그래밍 언어에 대입된 것이다.

-> 즉, 람다식은 함수를 간결하게 만들기 위해 사용한다!

람다식은 익명 메소드를 만들기 위해 사용하며, 람다식으로 만드는 익명 메소드는 '무명 함수'라고 부른다.

2. 익명 메서드

보통 메서드는 한정자가 없어도, 반환할 값이 없어도(void), 매개변수가 없어도 괜찮지만 이름은 있어야 한다. 하지만 익명 메서드는 '이름이 없는 메서드'를 뜻한다.

익명메서드는 delegate 키워드를 이용하여 선언한다.
대리자_인스턴스 = delegate (매개변수_목록) { //실행할 코드 }

예시를 통해 익명 메서드의 사용을 알아보자.
먼저, 대리자를 사용하여 '더하기 기능'을 구현한 코드이다.

namespace LambdaTest
{
    //대리자 선언
    delegate int MyDelegate(int a, int b);

    class Calculator
    {
        //대리자가 참조할 인스턴스 메서드
        public int Plus(int a, int b)
        {
            return a + b;
        }
    }

    internal class Program
    {    
        static void Main(string[] args)
        {
            Calculator Calc = new Calculator();
            MyDelegate Callback;

            Callback = new MyDelegate(Calc.Plus);
            //메서드를 호출하듯 대라자를 사용
            Console.WriteLine(Callback(3,4));
        }
    }
}

이를 익명 메서드를 사용한 코드로 수정해보았다.

namespace LambdaTest
{
    delegate int Calculator(int a, int b);
    internal class Program
    {    
        static void Main(string[] args)
        {
            Calculator Calc;
            Calc = delegate (int a, int b)
            {
                return a + b;
            };

            Console.WriteLine($"3 + 4 = {Calc(3,4)}");
        }
    }
}

확실히 코드가 보다 간결해졌다. 이것이 익명 메서드의 활용이다. ㄴ 쓰임: 대리자가 참조할 메서드를 넘겨야 할 때 메서드가 두 번 다시 사용할 일이 없다고 판단되면 익명 메서드를 사용해주는 것이 좋다.

3. 람다식 예시

3.1 식 형식의 람다식

람다식은 익명 메서드를 만들기 위해 사용하는 것으로, 위에 익명 메서드를 사용하여 작성한 코드를 람다식으로 수정해보았다.
(a + b, a == b 등 연산자를 사용하는 '식 형식'의 람다식)

namespace LambdaTest
{
    internal class Program
    {
        //익명 메서드를 만들 때 필요한 대리자
        delegate int Calculate(int a, int b);
        
        static void Main(string[] args)
        {
            //두 개의 int형식 매개변수 a, b를 받아 이 둘을 더해 반환하는 익명 메서드를 람다식으로 만듦
            //C#컴파일러의 '형식 유추' 기능으로 매개변수의 형식을 제거할 수 있다.
            Calculate calc = (a, b) => a + b; 
            Console.WriteLine($"3 + 4 : {calc(3,4)}");
        }
    }
}

-> 처음 작성했던 코드에 비해 훨씬 간결해졌다!

3.2 문 형식의 람다식

식 형식의 람다식으로는 반환 형식이 없는 무명 함수를 만들 수 없지만, 문 형식의 람다식을 이용하면 가능하다. ㄴ 문장 형식의 람다식은 {와 }로 둘러싼다.

4. Func와 Action으로 더 간편하게 무명 함수 만들기

익명 메서드나 무명 함수를 만들기 위해 매번 별개의 대리자를 선언해야하는 번거로움을 해결하기 위해 .NET에 Func와 Action 대리자를 미리 선언해뒀다.

Func 대리자는 결과를 반환하는 메서드를!
Action 대리자는 결과를 반환하지 않는 메서드를 참조한다.

4.1 Func 대리자

  • .NET에 준비되어 있는 Func대리자 17가지 버전
public delegate TResult Func<out TResult>();
public delegate TResult Func<in T, out TResult>(T arg);
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
    ...
    public delegate TResult Func<in T1, in T2, ..., in T16, out TResult>(T1 arg1, T2 arg2, ..., T16 arg16);

ㄴ 모든 Func 대리자의 형식 매개변수 중 가장 마지막에 있는 것이 반환 형식이다

  • 예시
    ㄴ 입력 매개변수가 16개 이상이거나, ref나 out 한정자로 수식된 매개변수를 사용해야 하는 경우가 아니라면 별도의 대리자를 만들어 쓸 필요가 없다!

4.2 Action 대리자

  • .NET에 준비되어 있는 Func대리자 17가지 버전
public delegate void Action();
public delegate void Action<in T>(T obj);
...
public delegate void Action<in T1, in T2, ..., in T16>(T1 arg1, T2 arg2, ..., T16 arg16);

ㄴ Action 대리자는 Func와 달리 어떤 결과를 반환하는 것이 목적이 아니라 일련의 작업을 수행하는 것이 목적이기 때문에 반환 형식이 없다!!

5. 식으로 이루어지는 멤버

  • 메서드, 속성(인덱서), 생성자, 종료자는 모두 클래스의 멤버로서 본문이 {중괄호}로 만들어져 있다. 이러한 멤버의 본문을 식(Expression)만으로 구현할 수 있는데, 이렇게 식으로 구현된 멤버를 '식 본문 멤버(Expression-Bodied Member)'라고 한다.
  • 예시
using System;
using System.Collections.Generic;

namespace LambdaTest
{
    class FriendList 
    {
        private List<string> list = new List<string>();

        //메서드
        public void Add(string name) => list.Add(name); 
        public void Remove(string name ) => list.Remove(name);  
        public void PrintAll()
        {
            foreach(var s in list)
                Console.WriteLine(s);
        }

        //생성자
        public FriendList() => Console.WriteLine("FriendList() 생성");

        //종료자
        ~FriendList() => Console.WriteLine("~FriendList() 종료");

        //읽기 전용
        //public int Capacity => list.Capacity; 

        //속성
        public int Capacity 
        {
            get => list.Capacity;
            set => list.Capacity = value;
        }

        //읽기 전용
        //public string this[int index] => list[index];
        public string this[int index]
        {
            get => list[index];
            set => list[index] = value;
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            FriendList f = new FriendList();
            f.Add("철수");
            f.Add("형원");
            f.Add("민지");
            f.Remove("철수");
            f.PrintAll();

            Console.WriteLine($"{f.Capacity}");
            f.Capacity = 10;
            Console.WriteLine($"{f.Capacity}");

            Console.WriteLine($"{f[0]}");
            f[0] = "준혁";
            f.PrintAll();
        }
    }
}

List<T>의 Capacity 속성은 리스트가 저장할 수 있는 요소의 수를 나타내며, 내부 배열의 크기를 의미합니다.

6. 실습하기

  • 다음 코드에서 익명 메소드를 람다식으로 수정하기
namespace LambdaTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            int[] array = { 11, 22, 33, 44, 55 };

            foreach (int i in array)
            {
                Action action = new Action
                    (
                        delegate ()
                        {
                            Console.WriteLine(i * i);
                        }
                    );
                action.Invoke ();
            }
        }
    }
}
  • <이것이 c#이다> 14장 연습문제 풀이

📄참고자료
<이것이 c#이다> 3판 - 박상현 지음 (한빛미디어)

profile
Unity 개발자 취준생의 개발로그, Slow and steady wins the race !

0개의 댓글