방법: 대리자 선언, 인스턴스화 및 사용(C# 프로그래밍 가이드)How to: Declare, Instantiate, and Use a Delegate (C# Programming Guide)

C# 1.0 이상 버전에서는 다음 예제와 같이 대리자를 선언할 수 있습니다.In C# 1.0 and later, delegates can be declared as shown in the following example.

// Declare a delegate.
delegate void Del(string str);

// Declare a method with the same signature as the delegate.
static void Notify(string name)
{
    Console.WriteLine("Notification received for: {0}", name);
}
// Create an instance of the delegate.
Del del1 = new Del(Notify);

C# 2.0에서는 다음 예제와 같이 더욱 간단한 방법으로 이전 선언을 쓸 수 있습니다.C# 2.0 provides a simpler way to write the previous declaration, as shown in the following example.

// C# 2.0 provides a simpler way to declare an instance of Del.
Del del2 = Notify;

C# 2.0 이상 버전에서는 다음 예제와 같이 익명 메서드를 사용하여 delegate를 선언하고 초기화할 수도 있습니다.In C# 2.0 and later, it is also possible to use an anonymous method to declare and initialize a delegate, as shown in the following example.

// Instantiate Del by using an anonymous method.
Del del3 = delegate(string name)
    { Console.WriteLine("Notification received for: {0}", name); };

C# 3.0 이상에서는 다음 예제와 같이 람다 식을 사용하여 대리자를 선언하고 인스턴스화할 수도 있습니다.In C# 3.0 and later, delegates can also be declared and instantiated by using a lambda expression, as shown in the following example.

// Instantiate Del by using a lambda expression.
Del del4 = name =>  { Console.WriteLine("Notification received for: {0}", name); };

자세한 내용은 람다 식을 참조하세요.For more information, see Lambda Expressions.

다음 예제에서는 대리자를 선언, 인스턴스화 및 사용하는 방법을 보여 줍니다.The following example illustrates declaring, instantiating, and using a delegate. BookDB 클래스는 책 데이터베이스를 유지 관리하는 서점 데이터베이스를 캡슐화합니다.The BookDB class encapsulates a bookstore database that maintains a database of books. 그리고 데이터베이스의 모든 문고판 책을 찾아 각 책에 대해 대리자를 호출하는 ProcessPaperbackBooks 메서드를 표시합니다.It exposes a method, ProcessPaperbackBooks, which finds all paperback books in the database and calls a delegate for each one. 이때 사용되는 delegate 형식의 이름은 ProcessBookDelegate입니다.The delegate type that is used is named ProcessBookDelegate. Test 클래스는 이 클래스를 사용하여 문고판 책의 제목과 평균 가격을 인쇄합니다.The Test class uses this class to print the titles and average price of the paperback books.

대리자를 사용하면 서점 데이터베이스와 클라이언트 코드 간에 기능을 효율적으로 구분할 수 있습니다.The use of delegates promotes good separation of functionality between the bookstore database and the client code. 클라이언트 코드는 책이 저장되는 방식이나 서점 코드가 문고판 책을 찾는 방식을 알 수 없습니다.The client code has no knowledge of how the books are stored or how the bookstore code finds paperback books. 서점 코드는 발견된 문고판 책에 대해 수행되는 처리를 알 수 없습니다.The bookstore code has no knowledge of what processing is performed on the paperback books after it finds them.

예제Example

// A set of classes for handling a bookstore:
namespace Bookstore
{
    using System.Collections;

    // Describes a book in the book list:
    public struct Book
    {
        public string Title;        // Title of the book.
        public string Author;       // Author of the book.
        public decimal Price;       // Price of the book.
        public bool Paperback;      // Is it paperback?

        public Book(string title, string author, decimal price, bool paperBack)
        {
            Title = title;
            Author = author;
            Price = price;
            Paperback = paperBack;
        }
    }

    // Declare a delegate type for processing a book:
    public delegate void ProcessBookDelegate(Book book);

    // Maintains a book database.
    public class BookDB
    {
        // List of all books in the database:
        ArrayList list = new ArrayList();

        // Add a book to the database:
        public void AddBook(string title, string author, decimal price, bool paperBack)
        {
            list.Add(new Book(title, author, price, paperBack));
        }

        // Call a passed-in delegate on each paperback book to process it: 
        public void ProcessPaperbackBooks(ProcessBookDelegate processBook)
        {
            foreach (Book b in list)
            {
                if (b.Paperback)
                    // Calling the delegate:
                    processBook(b);
            }
        }
    }
}


// Using the Bookstore classes:
namespace BookTestClient
{
    using Bookstore;

    // Class to total and average prices of books:
    class PriceTotaller
    {
        int countBooks = 0;
        decimal priceBooks = 0.0m;

        internal void AddBookToTotal(Book book)
        {
            countBooks += 1;
            priceBooks += book.Price;
        }

        internal decimal AveragePrice()
        {
            return priceBooks / countBooks;
        }
    }

    // Class to test the book database:
    class Test
    {
        // Print the title of the book.
        static void PrintTitle(Book b)
        {
            System.Console.WriteLine("   {0}", b.Title);
        }

        // Execution starts here.
        static void Main()
        {
            BookDB bookDB = new BookDB();

            // Initialize the database with some books:
            AddBooks(bookDB);

            // Print all the titles of paperbacks:
            System.Console.WriteLine("Paperback Book Titles:");

            // Create a new delegate object associated with the static 
            // method Test.PrintTitle:
            bookDB.ProcessPaperbackBooks(PrintTitle);

            // Get the average price of a paperback by using
            // a PriceTotaller object:
            PriceTotaller totaller = new PriceTotaller();

            // Create a new delegate object associated with the nonstatic 
            // method AddBookToTotal on the object totaller:
            bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);

            System.Console.WriteLine("Average Paperback Book Price: ${0:#.##}",
                    totaller.AveragePrice());
        }

        // Initialize the book database with some test books:
        static void AddBooks(BookDB bookDB)
        {
            bookDB.AddBook("The C Programming Language", "Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true);
            bookDB.AddBook("The Unicode Standard 2.0", "The Unicode Consortium", 39.95m, true);
            bookDB.AddBook("The MS-DOS Encyclopedia", "Ray Duncan", 129.95m, false);
            bookDB.AddBook("Dogbert's Clues for the Clueless", "Scott Adams", 12.00m, true);
        }
    }
}
/* Output:
Paperback Book Titles:
   The C Programming Language
   The Unicode Standard 2.0
   Dogbert's Clues for the Clueless
Average Paperback Book Price: $23.97
*/

강력한 프로그래밍Robust Programming

  • 대리자 선언Declaring a delegate.

    다음 문은 새 대리자 형식을 선언합니다.The following statement declares a new delegate type.

    public delegate void ProcessBookDelegate(Book book);
    

    각 대리자 형식은 인수의 수와 형식 및 캡슐화 가능한 메서드의 형식과 반환 값을 설명합니다.Each delegate type describes the number and types of the arguments, and the type of the return value of methods that it can encapsulate. 새 인수 형식 또는 반환 값 형식 집합이 필요할 때마다 새 대리자 형식을 선언해야 합니다.Whenever a new set of argument types or return value type is needed, a new delegate type must be declared.

  • 대리자 인스턴스화Instantiating a delegate.

    대리자 형식을 선언한 후에는 대리자 개체를 생성하여 특정 메서드와 연결해야 합니다.After a delegate type has been declared, a delegate object must be created and associated with a particular method. 이전 예제의 경우 다음 예제와 같이 PrintTitle 메서드를 ProcessPaperbackBooks 메서드에 전달하여 이 작업을 수행합니다.In the previous example, you do this by passing the PrintTitle method to the ProcessPaperbackBooks method as in the following example:

    bookDB.ProcessPaperbackBooks(PrintTitle);
    

    이렇게 하면 정적 메서드 Test.PrintTitle에 연결된 새 대리자 개체가 생성됩니다.This creates a new delegate object associated with the static method Test.PrintTitle. 마찬가지로 개체 totaller의 비정적 메서드 AddBookToTotal도 다음 예제와 같이 전달됩니다.Similarly, the non-static method AddBookToTotal on the object totaller is passed as in the following example:

    bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);
    

    두 경우 모두 새 대리자 개체가 ProcessPaperbackBooks 메서드로 전달됩니다.In both cases a new delegate object is passed to the ProcessPaperbackBooks method.

    대리자를 만든 후에도 대리자가 연결된 메서드는 변경되지 않습니다. 대리자 개체는 변경이 불가능합니다.After a delegate is created, the method it is associated with never changes; delegate objects are immutable.

  • 대리자 호출Calling a delegate.

    생성된 대리자 개체는 대개 대리자를 호출하는 다른 코드로 전달됩니다.After a delegate object is created, the delegate object is typically passed to other code that will call the delegate. 대리자 개체의 이름 뒤에 대리자로 전달할 인수를 괄호로 묶어 추가한 형식을 사용하여 대리자 개체를 호출합니다.A delegate object is called by using the name of the delegate object, followed by the parenthesized arguments to be passed to the delegate. 아래에 대리자 호출의 예가 나와 있습니다.Following is an example of a delegate call:

    processBook(b);
    

    대리자는 이 예제와 같이 동기적으로 호출할 수도 있고 BeginInvokeEndInvoke 메서드를 사용하여 비동기적으로 호출할 수도 있습니다.A delegate can be either called synchronously, as in this example, or asynchronously by using BeginInvoke and EndInvoke methods.

참고 항목See also