본문 바로가기
카테고리 없음

delegate Func 란?

by leo21c 2026. 6. 16.

MFC 개발자분들이 매일 사용하시던 '함수 포인터(Function Pointer)' 개념이 C#에서 가장 현대적이고 안전하게 진화한 형태라고 보시면 됩니다.

이 문법이 의미하는 바를 각 키워드와 MFC 개념을 매핑하여 명쾌하게 풀어드리겠습니다.

## 1. MFC 함수 포인터 vs C# Func 대리자

  • MFC 방식 (typedef): 특정 함수를 변수처럼 넘기려면 리턴 타입과 파라미터를 명시한 typedef를 매번 선언해야 했습니다. 32비트/64비트 환경이나 호출 규약(__stdcall, __cdecl)에 따라 컴파일 에러가 나기도 쉬웠죠.
C++
 
// MFC 스타일: 매번 타입을 정의해야 함
typedef int (*MY_CALC_FUNC)(double); 
  • .NET 8 방식 (Func): 프레임워크가 자주 쓰는 함수 포인터 형태를 제네릭(Generic, 구조체의 템플릿과 유사)으로 미리 다 만들어 두었습니다. 개발자는 typedef 정의 없이 그냥 Func<double, int>라고 적기만 하면 됩니다.

## 2. 정의문 한 줄씩 해부하기

C#
 
public delegate TResult Func<in T, out TResult>(T arg);

이 짧은 문장에 담긴 현대 C#의 핵심 메커니즘은 다음과 같습니다.

### ① delegate (대리자)

C++의 typedef 함수 포인터 선언과 같습니다. "이것은 일반 데이터 변수가 아니라, 함수의 메모리 주소를 담을 수 있는 대리자 변수 타입이다"라고 선언하는 것입니다.

### ② Func<in T, out TResult> (제네릭 파라미터)

  • <...>: C++의 템플릿(template <typename T>)과 같습니다. 어떤 데이터 타입이든 유연하게 받아들이겠다는 뜻입니다.
  • in T: 함수가 입력받을 매개변수(Argument)의 타입입니다. in 키워드는 반공변성(Contravariance)을 의미하며, "입력값은 더 넓은 데이터 타입(부모 클래스)도 안전하게 호환된다"는 것을 컴파일러에게 알려줍니다.
  • out TResult: 함수의 최종 리턴(반환) 타입입니다. out 키워드는 공변성(Covariance)을 의미하며, "결과값은 더 구체적인 타입(자식 클래스)으로 안전하게 내보낼 수 있다"는 뜻입니다.

### ③ (T arg)

이 함수 포인터가 가리킬 실제 함수의 매개변수 구조입니다. 위에서 정의한 T 타입의 변수 arg를 하나 입력받겠다는 뜻입니다.

## 3. 실무 코드 예시 (데이터 처리)

이 Func 대리자가 실제 전력 제어 소프트웨어에서 어떻게 강력하게 쓰이는지 구체적인 예시를 보여드리겠습니다.

장치에서 올라온 Raw 값을 받아서, 특정 규칙이나 배율을 적용해 변환 결과를 리턴하는 가상의 변환 엔진 구조입니다.

C#
 
public class CmrDataProcessor
{
    // Func<double, double> 변수는: 
    // "double을 입력받아서 double을 리턴하는 모든 함수"를 담을 수 있는 함수 포인터입니다.
    public double ApplyCalibration(double rawCurrent, Func<double, double> calibrationAlgorithm)
    {
        // 넘겨받은 함수 포인터(대리자)를 실행하여 결과를 리턴
        return calibrationAlgorithm(rawCurrent);
    }
}

이제 이 함수를 호출할 때, 과거 MFC처럼 복잡하게 함수 주소(&)를 넘길 필요 없이 현대 C#의 람다식(Lambda Expression)을 이용해 익명 함수를 한 줄 만에 즉석에서 주입할 수 있습니다.

C#
 
var processor = new DataProcessor();
double rawData = 1000.0; // 장치에서 읽은 1000 [cite: 33, 39]

// 예시 1: 오차율 1.02배를 곱하는 알고리즘 포인터를 즉석 주입
double result1 = processor.ApplyCalibration(rawData, x => x * 1.02);

// 예시 2: 특정 임계치(800)를 넘으면 값을 보정하는 복잡한 알고리즘 포인터 주입
double result2 = processor.ApplyCalibration(rawData, x => {
    if (x > 800) return x - 50;
    return x;
});

## 💡 MFC 개발자를 위한 최종 요약

public delegate TResult Func<in T, out TResult>(T arg);는

**"어떤 타입(T)이든 인자로 딱 하나 입력받아서, 원하는 타입(TResult)으로 결과를 돌려주는 '표준화된 함수 포인터 변수 뼈대'"**를 의미합니다.

앞서 학습하신 ResiliencePipeline 내부에서 ExecuteAsync를 호출할 때나, IServiceCollection에서 런타임에 동적으로 객체를 생성하는 팩토리 패턴을 짤 때 이 Func 대리자가 람다식과 결합하여 핵심적인 역할을 수행하게 됩니다.

LIST