나 개발자 진짜 되냐?

[ C# 기본 문법 22 ] 델리게이트, 람다 및 LINQ 본문

C# 을 맛보았어요!/문법정리를 해보았어요!

[ C# 기본 문법 22 ] 델리게이트, 람다 및 LINQ

Snow Rabbit 2024. 9. 23. 23:49

 

이번 글에서는 

 

델리게이트

람다

LINQ

 

라는 세 친구의 개념과 사용법을 알아보자!


 

🌟 델리게이트 🌟

delegate는

메서드를 참조하는 타입이다.

함수 포인터라고 불리며

 

메서드를 매개변수로 전달하거나 변수에 할당할 수 있다.

 

 

//사용시 앞에 델리게이트를 써주고 뒤에 메서드를 써준다.
delegate int Calculate(int x, int y);


//메서드 생성, 델리게이트 메서드의 형식과 동일해야함
static int Add(int x, int y)
{
    return x + y;
}

class Program
{
    static void Main()
    {
        // 메서드 등록, 메서드 연결
        Calculate calc = Add;

        // 델리게이트 사용
        int result = calc(3, 5);
        Console.WriteLine("결과: " + result);
    }
}

접근이 애매할 때 사용하면 더할 나위 없는 친구이다.

 

이렇게 두 개씩 써줄 수도 있다.

delegate void MyDelegate(string message);

static void Method1(string message)
{
    Console.WriteLine("Method1: " + message);
}

static void Method2(string message)
{
    Console.WriteLine("Method2: " + message);
}

class Program
{
    static void Main()
    {
        // 델리게이트 인스턴스 생성 및 메서드 등록
        MyDelegate myDelegate = Method1;
        //하나 더 연결 한번에 여러개의 메서드 사용 가능
        myDelegate += Method2;

        // 델리게이트 호출
        myDelegate("Hello!");

    }
}

 

관련 예제이다.

// 델리게이트 선언
public delegate void EnemyAttackHandler(float damage);

// 적 클래스
public class Enemy
{
    // 공격 이벤트
    public event EnemyAttackHandler OnAttack;

    // 적의 공격 메서드
    public void Attack(float damage)
    {
        // 이벤트 호출
        OnAttack?.Invoke(damage);
				// null 조건부 연산자
				// null 참조가 아닌 경우에만 멤버에 접근하거나 메서드를 호출
                // null 이면 실행 안하고, 아니면 invoke해줄게!
    }
}

// 플레이어 클래스
public class Player
{
    // 플레이어가 받은 데미지 처리 메서드
    public void HandleDamage(float damage)
    {
        // 플레이어의 체력 감소 등의 처리 로직
        Console.WriteLine("플레이어가 {0}의 데미지를 입었습니다.", damage);
    }
}

// 게임 실행
static void Main()
{
    // 적 객체 생성
    Enemy enemy = new Enemy();

    // 플레이어 객체 생성
    Player player = new Player();

    // 플레이어의 데미지 처리 메서드를 적의 공격 이벤트에 추가
    enemy.OnAttack += player.HandleDamage;

    // 적의 공격
    enemy.Attack(10.0f);
}

여기서는 event라는 친구가 나오는데

이 친구는 할당연산자, 즉 =을 사용할 수 없고

+= ,  -= 만 사용이 가능하다.

클래스 외부에서는 직접 이벤트를 호출할 수 없다.

 

여기서 주로 봐야 하는 건

호출되는 과정이다

main을 보면서 하나씩 그려나가 보자!

 

 

🌟 람다 🌟

Lambda는 익명의 메서드를 만드는 방법

 

메서드의 이름 없이 메서드를 만들 수 있다.

 

어떻게?

참조로!

 

이 람다는 아까 델리게이트를 사용하여

변수 할당 또는 메서드의 매개변수로 전달할 수 있다.

 

(parameter_list) => expression

 

여기서 중요한 건 저 화살표이다.

 

Calculate calc = (x, y) => 
{	
		return x + y;
};

Calculate calc = (x, y) => x + y;

화살표를 해놓고 중괄호를 통해 여러 줄을 쓸 수 있다.

아래처럼 한 줄도 가능!

 

예시를 보며 익혀보자!

 

// 델리게이트 선언
public delegate void GameEvent();

// 이벤트 매니저 클래스
public class EventManager
{
    // 게임 시작 이벤트
    public event GameEvent OnGameStart;

    // 게임 종료 이벤트
    public event GameEvent OnGameEnd;

    // 게임 실행
    public void RunGame()
    {
        // 게임 시작 이벤트 호출
        OnGameStart?.Invoke();

        // 게임 실행 로직

        // 게임 종료 이벤트 호출
        OnGameEnd?.Invoke();
    }
}

// 게임 메시지 클래스
public class GameMessage
{
    public void ShowMessage(string message)
    {
        Console.WriteLine(message);
    }
}

// 게임 실행
static void Main()
{
    // 이벤트 매니저 객체 생성
    EventManager eventManager = new EventManager();

    // 게임 메시지 객체 생성
    GameMessage gameMessage = new GameMessage();

    // 게임 시작 이벤트에 람다 식으로 메시지 출력 동작 등록
    eventManager.OnGameStart += () => gameMessage.ShowMessage("게임이 시작됩니다.");

    // 게임 종료 이벤트에 람다 식으로 메시지 출력 동작 등록
    eventManager.OnGameEnd += () => gameMessage.ShowMessage("게임이 종료됩니다.");

    // 게임 실행
    eventManager.RunGame();
}

 

람다를 굳이 쓰는 이유가 뭘까?

 

함수를 만들어서 연결하는 과정보다 쉽다.

 

🌟 Func &  Action 🌟

 

Func

값을 반환하는 메서드를 나타내는 델리게이트

 

< int를 입력받아 int로 반환 >

< 입력받고, 반환하고>

 

// Func를 사용하여 두 개의 정수를 더하는 메서드
int Add(int x, int y)
{
    return x + y;
}

// Func를 이용한 메서드 호출
Func<int, int, int> addFunc = Add;
int result = addFunc(3, 5);
Console.WriteLine("결과: " + result);

여기서는 int가 3개인데

앞에 두 개가 매개변수 마지막 한 개가 반환값이다.

 

Action

값을 반환하지 않는 메서드를 나타내는 델리게이트

 

< int를 입력받아 두 개어도 다 입력받아 매개변수인 셈 >

얜 반환하지 않기 때문

// Action을 사용하여 문자열을 출력하는 메서드
void PrintMessage(string message)
{
    Console.WriteLine(message);
}

// Action을 이용한 메서드 호출
Action<string> printAction = PrintMessage;
printAction("Hello, World!");

 

이렇게 Func와 Action을 해주면

변화를 가질 때마다 콜백이 된다.

 

그래서 우리가 굳이 조건을 걸지 않아도?

알아서 값이 변할 때마다

그에 맞는 행동을 취해준다.

 

그래서 얘네들은 정말 자주 쓰인다!

 

이 친구들이 뭐라고!?!?

메서드를 저장하는 기능!!

 

🌟 LINQ 🌟

(Language Integrated Query)

.NET 프레임워크에서 제공되는 쿼리 언어 확장

 

간단하게 말하면

데이터 모아있는 소스들한테

쿼리를 던진다.

 

쿼리란

 데이터베이스 등에서 원하는 정보를 검색하기 위해 요청하는 것을 말한다.

 

구조는

var result = from 변수 in 데이터소스
             [where 조건식]
             [orderby 정렬식 [, 정렬식...]]
             [select 식];

 

DB랑 굉장히 비슷하다.

 

select : 조회할 데이터 지정

orderby : 정렬 방식 지정

where : 조건식을 지정하여 데이터 필터링

from : 데이터 소스 지정

var : 결과의 자료형을 자동으로 추론

 

// 데이터 소스 정의 (컬렉션)
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

// 쿼리 작성 (선언적인 구문)
var evenNumbers = from num in numbers //하나씩 꺼내올건데
                  where num % 2 == 0
                  select num;

// 쿼리 실행 및 결과 처리
foreach (var num in evenNumbers)
{
    Console.WriteLine(num);
}

 

DB공부를 조금 해본 나라서

다행히 이 부분이 조금은 이해가 갈..

줄 알았는데 또 C#이랑 섞이니

 

LINQ 너란 녀석도.. 쉽지 않구나

 

Func와 Action은

굉장히 간편해 보였다.

더 익숙해져서

꼭 실전에서 활용해보고 싶다 (●'◡'●)