대리자 사용(C# 프로그래밍 가이드)Using Delegates (C# Programming Guide)

대리자는 C 및 C++의 함수 포인터처럼 메서드를 안전하게 캡슐화하는 형식입니다.A delegate is a type that safely encapsulates a method, similar to a function pointer in C and C++. 함수 포인터와는 달리 대리자는 개체 지향적이고 형식이 안전하며 보안이 유지됩니다.Unlike C function pointers, delegates are object-oriented, type safe, and secure. 대리자의 형식은 대리자의 이름으로 정의됩니다.The type of a delegate is defined by the name of the delegate. 다음 예제에서는 string을 인수로 사용하고 void를 반환하는 메서드를 캡슐화할 수 있는 Del 대리자를 선언합니다.The following example declares a delegate named Del that can encapsulate a method that takes a string as an argument and returns void:

public delegate void Del(string message);

대리자 개체는 일반적으로 대리자가 래핑할 메서드의 이름을 제공하거나 무명 메서드를 사용하여 생성합니다.A delegate object is normally constructed by providing the name of the method the delegate will wrap, or with an anonymous Method. 대리자를 인스턴스화하고 나면 대리자에 대한 메서드 호출이 대리자에 의해 해당 메서드로 전달됩니다.Once a delegate is instantiated, a method call made to the delegate will be passed by the delegate to that method. 호출자가 대리자에게 전달한 매개 변수가 메서드로 전달되며 메서드의 반환 값(있는 경우)이 대리자에 의해 호출자로 반환됩니다.The parameters passed to the delegate by the caller are passed to the method, and the return value, if any, from the method is returned to the caller by the delegate. 이 과정을 대리자 호출이라고 합니다.This is known as invoking the delegate. 인스턴스화된 대리자는 래핑된 메서드 자체인 것처럼 호출할 수 있습니다.An instantiated delegate can be invoked as if it were the wrapped method itself. 예를 들면 다음과 같습니다.For example:

// Create a method for a delegate.
public static void DelegateMethod(string message)
{
    System.Console.WriteLine(message);
}
// Instantiate the delegate.
Del handler = DelegateMethod;

// Call the delegate.
handler("Hello World");

대리자 형식은 .NET Framework의 Delegate 클래스에서 파생되며,Delegate types are derived from the Delegate class in the .NET Framework. 봉인되어 있으므로 Delegate에서는 파생될 수 없으며 해당 클래스에서 사용자 지정 클래스를 파생할 수도 없습니다.Delegate types are sealed—they cannot be derived from— and it is not possible to derive custom classes from Delegate. 인스턴스화된 대리자는 개체이므로 매개 변수로 전달하거나 속성에 할당할 수 있습니다.Because the instantiated delegate is an object, it can be passed as a parameter, or assigned to a property. 따라서 메서드가 대리자를 매개 변수로 허용하고 나중에 대리자를 호출할 수 있습니다.This allows a method to accept a delegate as a parameter, and call the delegate at some later time. 비동기 콜백이라는 이러한 방식은 긴 프로세스 완료 시 호출자에게 알림을 제공하는 일반적인 방법입니다.This is known as an asynchronous callback, and is a common method of notifying a caller when a long process has completed. 이러한 방식으로 대리자를 사용하면 대리자를 사용하는 코드가 사용 중인 메서드의 구현을 확인하지 않아도 됩니다.When a delegate is used in this fashion, the code using the delegate does not need any knowledge of the implementation of the method being used. 이 기능은 캡슐화 인터페이스에서 제공하는 기능과 비슷합니다.The functionality is similar to the encapsulation interfaces provide.

콜백은 사용자 지정 비교 메서드를 정의하고 해당 대리자를 정렬 메서드로 전달할 때도 일반적으로 사용됩니다.Another common use of callbacks is defining a custom comparison method and passing that delegate to a sort method. 이 경우 호출자의 코드를 정렬 알고리즘의 일부분으로 포함할 수 있습니다.It allows the caller's code to become part of the sort algorithm. 다음 예제 메서드는 Del 형식을 매개 변수로 사용합니다.The following example method uses the Del type as a parameter:

public void MethodWithCallback(int param1, int param2, Del callback)
{
    callback("The number is: " + (param1 + param2).ToString());
}

위에서 작성된 대리자를 해당 메서드로 전달할 수 있습니다.You can then pass the delegate created above to that method:

MethodWithCallback(1, 2, handler);

그러면 콘솔에 다음 출력이 표시됩니다.and receive the following output to the console:

The number is: 3

대리자를 추상화로 사용하는 경우 MethodWithCallback이 콘솔을 직접 호출할 필요가 없으며 콘솔을 호출하기 위해 이 메서드를 지정하지 않아도 됩니다.Using the delegate as an abstraction, MethodWithCallback does not need to call the console directly—it does not have to be designed with a console in mind. MethodWithCallback은 단순히 문자열을 준비하여 다른 메서드로 전달할 뿐입니다.What MethodWithCallback does is simply prepare a string and pass the string to another method. 위임된 메서드는 매개 변수를 필요한 수만큼 사용할 수 있으므로 이러한 방식은 특히 유용합니다.This is especially powerful since a delegated method can use any number of parameters.

인스턴스 메서드를 래핑하기 위한 대리자를 생성할 때 해당 대리자는 인스턴스와 메서드를 모두 참조합니다.When a delegate is constructed to wrap an instance method, the delegate references both the instance and the method. 대리자는 래핑 대상 메서드 이외의 인스턴스 형식은 알 수 없으므로 해당 개체에 대리자 서명과 일치하는 메서드가 있으면 모든 개체 형식을 참조할 수 있습니다.A delegate has no knowledge of the instance type aside from the method it wraps, so a delegate can refer to any type of object as long as there is a method on that object that matches the delegate signature. 정적 메서드를 래핑하기 위해 생성하는 대리자는 메서드만 참조합니다.When a delegate is constructed to wrap a static method, it only references the method. 다음의 선언을 살펴보세요.Consider the following declarations:

public class MethodClass
{
    public void Method1(string message) { }
    public void Method2(string message) { }
}

이제는 위에 나와 있는 정적 DelegateMethod와 함께 3개 메서드를 Del 인스턴스로 래핑할 수 있습니다.Along with the static DelegateMethod shown previously, we now have three methods that can be wrapped by a Del instance.

대리자는 호출 시 둘 이상의 메서드를 호출할 수 있습니다.A delegate can call more than one method when invoked. 이러한 호출을 멀티캐스트라고 합니다.This is referred to as multicasting. 대리자의 메서드 목록(호출 목록)에 메서드를 더 추가하려는 경우 더하기 또는 더하기 대입 연산자('+' 또는 '+=')를 사용하여 대리자만 두 개 더 추가하면 됩니다.To add an extra method to the delegate's list of methods—the invocation list—simply requires adding two delegates using the addition or addition assignment operators ('+' or '+='). 예를 들면 다음과 같습니다.For example:

MethodClass obj = new MethodClass();
Del d1 = obj.Method1;
Del d2 = obj.Method2;
Del d3 = DelegateMethod;

//Both types of assignment are valid.
Del allMethodsDelegate = d1 + d2;
allMethodsDelegate += d3;

이 시점에서 allMethodsDelegate의 호출 목록에는 Method1, Method2, DelegateMethod의 3개 메서드가 포함되어 있습니다.At this point allMethodsDelegate contains three methods in its invocation list—Method1, Method2, and DelegateMethod. 원래 대리자 3개(d1, d2, d3)는 그대로 유지됩니다.The original three delegates, d1, d2, and d3, remain unchanged. allMethodsDelegate를 호출하면 3개 메서드가 모두 순서대로 호출됩니다.When allMethodsDelegate is invoked, all three methods are called in order. 대리자가 참조 매개 변수를 사용하는 경우 참조는 각 3개 메서드에 순서대로 전달되며 메서드 하나의 변경 내용은 다음 메서드에도 표시됩니다.If the delegate uses reference parameters, the reference is passed sequentially to each of the three methods in turn, and any changes by one method are visible to the next method. 메서드 중 하나라도 메서드 내에서 catch되지 않은 예외를 throw하면 해당 예외가 대리자의 호출자에게 해당 예외가 전달되며 호출 목록의 후속 메서드는 호출되지 않습니다.When any of the methods throws an exception that is not caught within the method, that exception is passed to the caller of the delegate and no subsequent methods in the invocation list are called. 반환 값 및/또는 out 매개 변수를 포함하는 대리자는 마지막으로 호출한 메서드의 반환 값과 매개 변수를 반환합니다.If the delegate has a return value and/or out parameters, it returns the return value and parameters of the last method invoked. 호출 목록에서 메서드를 제거하려면 감소 또는 감소 대입 연산자('-' 또는 '-=')를 사용합니다.To remove a method from the invocation list, use the decrement or decrement assignment operator ('-' or '-='). 예를 들면 다음과 같습니다.For example:

//remove Method1
allMethodsDelegate -= d1;

// copy AllMethodsDelegate while removing d2
Del oneMethodDelegate = allMethodsDelegate - d2;

대리자 형식은 System.Delegate에서 파생되므로 해당 클래스로 정의되는 메서드와 속성을 대리자에서 호출할 수 있습니다.Because delegate types are derived from System.Delegate, the methods and properties defined by that class can be called on the delegate. 예를 들어 대리자의 호출 목록에 있는 메서드 수를 확인하려는 경우 다음과 같이 코드를 작성하면 됩니다.For example, to find the number of methods in a delegate's invocation list, you may write:

int invocationCount = d1.GetInvocationList().GetLength(0);

호출 목록에 메서드가 둘 이상 포함된 대리자는 MulticastDelegate의 하위 클래스인 System.Delegate에서 파생됩니다.Delegates with more than one method in their invocation list derive from MulticastDelegate, which is a subclass of System.Delegate. 두 클래스가 모두 GetInvocationList를 지원하므로 위의 코드는 두 경우에 모두 사용 가능합니다.The above code works in either case because both classes support GetInvocationList.

멀티캐스트 대리자는 이벤트 처리에서 광범위하게 사용됩니다.Multicast delegates are used extensively in event handling. 이벤트 소스 개체는 해당 이벤트를 받도록 등록된 받는 사람 개체에 이벤트 알림을 보냅니다.Event source objects send event notifications to recipient objects that have registered to receive that event. 이벤트를 등록하기 위해 받는 사람은 이벤트를 처리하도록 설계된 메서드를 만든 다음 해당 메서드의 대리자를 만들어 이벤트 소스로 전달합니다.To register for an event, the recipient creates a method designed to handle the event, then creates a delegate for that method and passes the delegate to the event source. 소스는 이벤트 발생 시 대리자를 호출합니다.The source calls the delegate when the event occurs. 그러면 대리자가 받는 사람에 대해 이벤트 처리 메서드를 호출하여 이벤트 데이터를 전달합니다.The delegate then calls the event handling method on the recipient, delivering the event data. 지정된 이벤트의 대리자 형식은 이벤트 소스에 의해 정의됩니다.The delegate type for a given event is defined by the event source. 자세한 내용은 이벤트를 참조하세요.For more, see Events.

컴파일 시간에 할당된 서로 다른 형식의 두 대리자를 비교하면 컴파일 오류가 발생합니다.Comparing delegates of two different types assigned at compile-time will result in a compilation error. 대리자 인스턴스가 정적 System.Delegate 형식이면 비교는 허용되지만 런타임에서 false가 반환됩니다.If the delegate instances are statically of the type System.Delegate, then the comparison is allowed, but will return false at run time. 예:For example:

delegate void Delegate1();
delegate void Delegate2();

static void method(Delegate1 d, Delegate2 e, System.Delegate f)
{
    // Compile-time error.
    //Console.WriteLine(d == e);

    // OK at compile-time. False if the run-time type of f 
    // is not the same as that of d.
    System.Console.WriteLine(d == f);
}

참고 항목See Also

C# 프로그래밍 가이드C# Programming Guide
대리자Delegates
대리자의 가변성 사용Using Variance in Delegates
대리자의 가변성Variance in Delegates
Func 및 Action 제네릭 대리자에 가변성 사용Using Variance for Func and Action Generic Delegates
이벤트Events