방법: 대리자 선언, 인스턴스화 및 사용(C# 프로그래밍 가이드)
업데이트: 2007년 11월
C# 1.0 이상에서는 다음과 같이 대리자를 선언할 수 있습니다.
public delegate void Del<T>(T item);
public void Notify(int i) { }
Del<int> d1 = new Del<int>(Notify);
C# 2.0 이상에서는 이 간단한 구문을 통해 무명 메서드를 사용하여 대리자를 선언하고 초기화할 수도 있습니다.
Del<int> d2 = Notify;
C# 3.0 이상에서는 람다 식을 사용하여 대리자를 선언하고 인스턴스화할 수도 있습니다. 자세한 내용은 람다 식(C# 프로그래밍 가이드)을 참조하십시오.
다음 예제에서는 대리자 선언, 인스턴스화 및 사용에 대해 설명합니다. BookDB 클래스는 설명서 데이터베이스를 관리하는 설명서 저장소 데이터베이스를 캡슐화합니다. 데이터베이스에서 모든 페이퍼백 설명서를 찾아 각 설명서에 대해 대리자를 호출하는 ProcessPaperbackBooks 메서드를 표시합니다. 사용되는 delegate 형식의 이름은 ProcessBookDelegate입니다. 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 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 TestBookDB
{
// 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
*/
강력한 프로그래밍
대리자 선언
다음 문은 새 대리자 형식을 선언합니다.
public delegate void ProcessBookDelegate(Book book);
각 대리자 형식은 인수의 형식과 수 그리고 캡슐화할 수 있는 메서드 반환 값의 형식에 대해 설명합니다. 인수 형식이나 반환 값 형식의 새 집합이 필요할 때마다 새 대리자 형식을 선언해야 합니다.
대리자 인스턴스화
대리자 형식을 선언한 후에는 대리자 개체를 만들어 특정 메서드와 결합해야 합니다. 위의 예제에서는 다음 예제와 같이 ProcessPaperbackBooks 메서드에 PrintTitle 메서드를 전달하여 이 작업을 수행합니다.
bookDB.ProcessPaperbackBooks(PrintTitle);
이렇게 하면 정적 메서드 Test.PrintTitle과 결합된 새 대리자 개체가 작성됩니다. 마찬가지로 totaller 개체에 대한 비정적 메서드 AddBookToTotal은 다음 예제와 같이 전달됩니다.
bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);
두 가지 경우 모두에서 새 대리자 개체는 ProcessPaperbackBooks 메서드로 전달됩니다.
대리자 개체는 변경할 수 없으므로 대리자를 만든 후에는 이와 결합된 메서드를 변경할 수 없습니다.
대리자 호출
대리자 개체를 만들면 대리자 개체는 일반적으로 대리자를 호출할 다른 코드에 전달됩니다. 대리자 개체의 이름을 사용하여 대리자 개체를 호출하면 괄호 안의 인수가 대리자로 전달됩니다. 다음은 대리자 호출을 보여 주는 예제입니다.
processBook(b);
대리자는 이 예제에서와 같이 동기적으로 호출할 수도 있고 BeginInvoke 및 EndInvoke 메서드를 사용하여 비동기적으로 호출할 수도 있습니다.