C#

[C#] Func, Action

Prooni 2024. 10. 11. 14:34

안녕하세요~

오늘은 C# Func, Action 에 대해 공부해요!

 

Func 와 Action을 이해하려면

람다식을 알아야하는데요!

 

람다식은 익명 메소드를 만들기 위해 사용해요!

람다식을 선언하는 형식은 다음과 같아요

매개변수_목록 => 식

매우 간단하죠?

 

익명 메소드를 만들려면 대리자가 필요해요!

 

익명 메소드에 대해 가물가물하시다면 아래 게시물을 참고하시면 도움이 될거에요!!

 

https://unityking.tistory.com/27

 

[C#] 대리자와 이벤트 (delegate 와 event)

안녕하세요~오늘은 C# 대리자와 이벤트를 공부해요! 대리자는 비서와 같은 역할이에요!만약 어떤 사람이 사장님과의 통화를 위해 회사로 전화를 했을 때사장님이 아닌 비서가 받았다고 해볼게

unityking.tistory.com

 

 

자 이제 익명 메소드를 람다식으로 만들어볼게요

delegate int Calculate(int a, int b)

//...

static void Main(string[] args)
{
	Calculate Calc = (a, b) => a + b;
}

짠 이렇게 매우 간결한 코드로 익명 메소드를 완성했어요.

()안에는 매개변수 목록이 들어가는데

형식을 써줘도 되지만

C# 컴파일러는 "형식유추(Type Inference)" 기능을 제공하기 때문에

위 코드처럼 매개 변수만 써줘도 됩니다!! 

 

그런데 람다식에 들어갈 코드가 한줄 이상이라면 어떻게 될까요??

이 경우에는 {}를 이용해서

"문 형식의 람다식"을 사용해요!

 

예제코드 첨부할게요

class MainApp
{
    delegate string Concatenate(string[] args);

    static void Main(string[] args)
    {
        Concatenate concat =
            (arr) =>
            {
                string result = "";
                foreach (string s in arr)
                {
                    result += s;
                }
                return result;
            };

        Console.WriteLine(concat(args));
    }
}

 

 

익명 메소드나 무명함수를 사용하기 위해서는

매번 별개의 대리자를 선언해야해요!

 

조금 번거롭죠?

 그래서 마이크로소프트는 .NET에 Func와 Action 대리자를 미리 선언해놨어요!!

 

Func와 Action에 대해 간단하게 먼저 설명하자면

Func는 결과를 반환하는 메소드를 참조하고

Action은 결과를 반환하지 않는 메소드를 참조해요!

 

 

Func 대리자

Func 대리자는 결과를 반환하는 메소드를 참조하기 위해 만들어졌어요모든 Func 대리자의 형식 매개변수가장 마지막에 있는것이 반환형식이에요!Func 대리자는 매개변수를 갖지 않는 것부터16개의 매개변수를 가지는 것까지 다양한 버전이 있답니다.

 

예시코드 첨부할게요.

class MainApp
{
    static void Main(string[] args)
    {
        Func<int> func1 = () => 10; // 매개변수 없는 Func
        Console.WriteLine(func1());

        Func<int, int> func2 = (x) => x * 2; // int형 매개변수 한개와 int형 반환값을 가지는 Func
        Console.WriteLine($"func2(4) : {func2(4)}");

        Func<double, double, double> func3 = (x, y) => x / y; //double형 매개변수 2개와 double형 반환값을 가지는 Func
        Console.WriteLine($"func3(22,7) : {func3(22, 7)}");
    }
}

 

 

Action 대리자

Action 대리자는 Func 대리자와 거의 똑같지만

반환형식이 없다는 것만 달라요!

Action대리자도 16개까지의 매개변수를 가질 수 있어서

다양한 버전이 있답니다!!

 

예시코드 첨부할게요.

class MainApp
{
    static void Main(string[] args)
    {
        Action act1 = () => Console.WriteLine("Action()"); // 매개변수가 없는 Action
        act1();

        int result = 0;
        Action<int> act2 = (x) => result = x * x; // int형 매개변수 1개를 가지는 Action
        act2(3);
        Console.WriteLine($"result : {result}");

        Action<double, double> act3 = (x, y) => // double형 매개변수 2개를 가지는 Action
        {
            double pi = x / y;
            Console.WriteLine($"Action<T1, T2>({x}, {y} : {pi})");
        };

        act3(22.0, 7.0);
    }
}

 

 

 

식 본문 멤버( Expression-Bodied Member )

 

메소드를 비롯한 인덱서, 생성자, 종료자의 본문을 식(expression)으로 구현할 수 있어요

이렇게 구현된 멤버를 Expression-Bodied Member라고 해요.

 

먼저 메소드를 식으로 표현해볼게요

class FriendList
{
	//...
    
    public void Add(string name) => list.Add(name);
    public void Remove(string name) => list.Remove(name);
}

 

 

 

생성자와 종료자를 식으로 구현하면 아래와 같아요.

public FriendList() => Console.WriteLine("FriendList()");
~FriendList() => Console.WriteLine("~FriendList()");

 

 

읽기전용 프로퍼티 및 인덱서를 식으로 구현한 코드는 아래와 같아요.

get 키워드를 생략할 수 있답니다.

public int capacity => list.Capacity; // 읽기 전용 프로퍼티 (get 생략)
public string this[int index] => list[index]; //읽기 전용 인덱서 (get 생략)

 

 

읽기와 쓰기가 모두 가능한 프로퍼티와 인덱서를 구현하려면 get, set 키워드를 명시해야해요

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

public string this[int index]
{
    get => list[index];
    set => list[index] = value;
}

 

 

예시코드를 첨부할게요.

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; // 읽기 전용 프로퍼티 (get 생략)

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

    // public string this[int index] => list[index]; //읽기 전용 인덱서 (get 생략)

    public string this[int index]
    {
        get => list[index];
        set => list[index] = value;
    }
}

class MainApp
{
    static void Main(string[] args)
    {
        FriendList obj = new FriendList();
        obj.Add("Eeny");
        obj.Add("Meeny");
        obj.Add("Miny");
        obj.Remove("Eeny");
        obj.PrintAll();

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

        Console.WriteLine($"{obj[0]}");
        obj[0] = "Moe";
        obj.PrintAll();
    }
}

'C#' 카테고리의 다른 글

[C#] LINQ  (1) 2024.10.13
[C#] 식 트리 (Expression Tree)  (0) 2024.10.11
[C#] 대리자와 이벤트 (delegate 와 event)  (5) 2024.10.10
[C#] 예외 처리  (1) 2024.10.09
[C#] Generic T 일반화 프로그래밍  (0) 2024.10.08