대리자를 선언, 인스턴스화, 사용하는 방법(C# 프로그래밍 가이드)

다음과 같은 메서드 중 하나라도 사용하여 대리자를 선언할 수 있습니다.

  • 대리자 형식을 선언하고 그와 일치하는 서명이 있는 메서드를 선언합니다.
// Declare a delegate.
delegate void NotifyCallback(string str);

// Declare a method with the same signature as the delegate.
static void Notify(string name)
{
    Console.WriteLine($"Notification received for: {name}");
}
// Create an instance of the delegate.
NotifyCallback del1 = new NotifyCallback(Notify);
  • 대리자 형식에 메서드 그룹을 할당합니다.
// C# 2.0 provides a simpler way to declare an instance of NotifyCallback.
NotifyCallback del2 = Notify;
  • 익명 메서드를 선언합니다.
// Instantiate NotifyCallback by using an anonymous method.
NotifyCallback del3 = delegate(string name)
    { Console.WriteLine($"Notification received for: {name}"); };
  • 다음의 람다 식을 사용합니다.
// Instantiate NotifyCallback by using a lambda expression.
NotifyCallback del4 = name =>  { Console.WriteLine($"Notification received for: {name}"); };

자세한 내용은 람다 식을 참조하세요.

다음 예제에서는 대리자를 선언, 인스턴스화 및 사용하는 방법을 보여 줍니다. BookDB 클래스는 책 데이터베이스를 유지 관리하는 서점 데이터베이스를 캡슐화합니다. 그리고 데이터베이스의 모든 문고판 책을 찾아 각 책에 대해 대리자를 호출하는 ProcessPaperbackBooks 메서드를 표시합니다. 이때 사용되는 delegate 형식의 이름은 ProcessBookCallback입니다. Test 클래스는 이 클래스를 사용하여 문고판 책의 제목과 평균 가격을 인쇄합니다.

대리자를 사용하면 서점 데이터베이스와 클라이언트 코드 간에 기능을 효율적으로 구분할 수 있습니다. 클라이언트 코드는 책이 저장되는 방식이나 서점 코드가 문고판 책을 찾는 방식을 알 수 없습니다. 서점 코드는 발견된 문고판 책에 대해 수행되는 처리를 알 수 없습니다.

예제

// 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 ProcessBookCallback(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(ProcessBookCallback 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)
        {
            Console.WriteLine($"   {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:
            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);

            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
*/

강력한 프로그래밍

  • 대리자 선언

    다음 문은 새 대리자 형식을 선언합니다.

    public delegate void ProcessBookCallback(Book book);
    

    각 대리자 형식은 인수의 수와 형식 및 캡슐화 가능한 메서드의 형식과 반환 값을 설명합니다. 새 인수 형식 또는 반환 값 형식 집합이 필요할 때마다 새 대리자 형식을 선언해야 합니다.

  • 대리자 인스턴스화

    대리자 형식을 선언한 후에는 대리자 개체를 생성하여 특정 메서드와 연결해야 합니다. 이전 예제의 경우 다음 예제와 같이 PrintTitle 메서드를 ProcessPaperbackBooks 메서드에 전달하여 이 작업을 수행합니다.

    bookDB.ProcessPaperbackBooks(PrintTitle);
    

    이렇게 하면 정적 메서드 Test.PrintTitle에 연결된 새 대리자 개체가 생성됩니다. 마찬가지로 개체 totaller의 비정적 메서드 AddBookToTotal도 다음 예제와 같이 전달됩니다.

    bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);
    

    두 경우 모두 새 대리자 개체가 ProcessPaperbackBooks 메서드로 전달됩니다.

    대리자를 만든 후에도 대리자가 연결된 메서드는 변경되지 않습니다. 대리자 개체는 변경이 불가능합니다.

  • 대리자 호출

    생성된 대리자 개체는 대개 대리자를 호출하는 다른 코드로 전달됩니다. 대리자 개체의 이름 뒤에 대리자로 전달할 인수를 괄호로 묶어 추가한 형식을 사용하여 대리자 개체를 호출합니다. 아래에 대리자 호출의 예가 나와 있습니다.

    processBook(b);
    

    대리자는 이 예제와 같이 동기적으로 호출할 수도 있고 BeginInvokeEndInvoke 메서드를 사용하여 비동기적으로 호출할 수도 있습니다.

참고 항목