[C#] Callback 함수

Lingtea_luv·2025년 4월 13일
0

C#

목록 보기
29/37
post-thumbnail

Callback 함수

함수를 직접 호출하는 것이 아닌, 다른 함수의 매개변수로 참조되어 참조한 함수가 호출될 때 내부에서 매개변수로써 호출되는 것

콜백함수를 간단히 말하면 다른 함수의 매개변수로 참조되어, 간접호출로써 실행되는 것을 의미한다. 이때 매개변수로 참조되는 방식은 익명 메서드, 화살표 함수, 델리게이트 등 여러가지가 있다. 먼저 Button 이라는 클래스에 콜백함수를 호출하기 위한 메서드를 선언해보자.

public class Button
{
    public void Click(Action callback)
    {
        if (callback != null) callback();
    }
}

위와 같이 Click 메서드에 일반화 델리게이트 Action 을 활용하여 콜백함수를 매개변수로 지정하고, 내부에서 콜백함수의 호출 조건을 작성하면 된다.

익명 메서드

static void Main(string[] args)
{
	Button anonyButton = new Button();
    anonyButton.Click(delegate { Console.WriteLine("익명"); });
}

익명메서드를 활용하면 매개변수에 콜백함수를 이름이 없는 함수로 지정하는 것이 가능하며, 이를 조금 더 간편하게 사용하기 위해 줄인 것이 화살표 함수이다.

화살표 함수

static void Main(string[] args)
{
	Button arrowButton = new Button();
    arrowButton.Click(() => { Console.WriteLine("화살표"); });
}

빈괄호 안에 들어가는 것은 콜백함수의 매개변수로 위에서 사용된 콜백함수는 반환형이 void이기에 비워둔 것이다.

함수 포인터 지정

public class File
{
    public void Save() => Console.WriteLine("저장");
    public void Load() => Console.WriteLine("불러오기");
}

static void Main(string[] args)
{
	File file = new File();
    Button saveButton = new Button();
    Button loadButton = new Button();
    
    saveButton.Click(file.Save); 
    loadButton.Click(file.Load); 
}

위처럼 특정 클래스의 멤버함수를 포인터로써 매개변수로 지정하는 것이 가능하며, 간단하게 콜백함수의 기능을 구현할 수 있다.

예시

회사에서 면접자가 면접관의 호출에 의해 들어가는 상황을 구현해보자

public class Interviewer
{
    public void Call(Action Secretary)
    {
        Console.WriteLine("면접관이 호출하다");
        Secretary();
    }
}

public class Company
{
    private Interviewer _interviewer;
    private Interviewee _interviewee;

    public Company()
    {
        _interviewer = new();
        _interviewee = new();
    }
    
    public void Interview()
    {
        _interviewer.Arrive(_interviewee.Receive);
    }
}

public class Interviewee
{
    public void Receive()
    {
        Console.WriteLine("면접 희망자가 호출을 받다");
    }
}

internal class Program
{
    static void Main(string[] args)
    {
        Company company = new Company();
        company.Interview();
    }
}
면접관이 호출하다
면접 희망자가 호출을 받다

콜백 함수 사용 의의

콜백함수는 동기적인 상황에서 어떤 작업의 결과를 전달하는 방식으로 사용된다. 위에서 사용된 코드를 예시로 들자면, 면접관이 Call 한 결과가 면접자의 receive로 전달된 것이다. 물론 동기적인 상황에서는 단순히 코드를 순서대로 나열하는 것으로 같은 상황을 연출할 수 있으니, 콜백함수의 사용의의에 대해 의문이 생길 것이다.

콜백함수의 진정한 의의는 비동기적인 상황에서의 활용으로부터 나온다. C#에서 콜백은 보통 델리게이트를 사용하여 구현되는데, 이 경우 메서드에 대한 안전한 참조를 가능하게 해주며 비동기적인 상황에서의 결과를 전달해주는데 효과적이다.

지금은 스레드(Thread)의 개념을 제대로 알지 못하기에 콜백함수의 의의는 스레드와 BeginInvoke에 대해 공부할 때 연관지어 다시 작성해보겠다.

델리게이트의 사용의의

C#에서 콜백은 델리게이트를 사용하여 구현한다고 했는데, 그 이유는 클래스 간의 결합도를 낮추는 방법이기 때문이다. 콜백은 클래스의 직접적인 참조로도 구현이 가능한데, 아래의 예시를 보자.

public class Interviewer
{
    private Interviewee interviewee;

    public Interviewer()
    {
        interviewee = new Interviewee();
    }
    
    public void Arrive()
    {
        Console.WriteLine("면접관이 도착하다");
        interviewee.Receive();
    }
}

public class Company
{
    private Interviewer _interviewer;
        
    public Company()
    {
        _interviewer = new();
    }
        
    public void Interview()
    {
        _interviewer.Arrive();
    }
}

public class Interviewee
{
    public void Receive()
    {
        Console.WriteLine("면접 희망자가 호출을 받다.");
    }
}
    
internal class Program
{
    static void Main(string[] args)
    {
        Company company = new Company();
        company.Interview();
    }
}
면접관이 호출하다
면접 희망자가 호출을 받다

Interviewer 클래스 내부에 Interviewee 클래스를 참조하여 Arrive 함수 내부에 직접 intervieweeRecieve를 넣었다.

물론 델리게이트를 사용해 구현한 것과 동일한 결과가 나오는 것을 확인할 수 있지만, 이 경우 클래스 간의 결합도가 높아지게 된다.

클래스 내부에서 다른 클래스 인스턴스를 생성할 경우 결합도가 높다고 말하기에, 델리게이트를 활용하여 콜백함수를 구현하는 것이 클래스 간 결합도를 낮추는데 도움이 될 것이다.

profile
뚠뚠뚠뚠

0개의 댓글