Vorgehensweise: Deklarieren, Instanziieren und Verwenden von Delegaten (C#-Programmierleitfaden)
Sie können Delegaten mit einer der folgenden Methoden deklarieren:
- Deklarieren Sie einen Delegattyp und eine Methode mit einer übereinstimmenden Signatur:
// 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);
- Weisen Sie einem Delegattyp eine Methodengruppe zu:
// C# 2.0 provides a simpler way to declare an instance of NotifyCallback.
NotifyCallback del2 = Notify;
- Deklarieren Sie eine anonyme Methode:
// Instantiate NotifyCallback by using an anonymous method.
NotifyCallback del3 = delegate(string name)
{ Console.WriteLine($"Notification received for: {name}"); };
- Verwenden Sie einen Lambdaausdruck:
// Instantiate NotifyCallback by using a lambda expression.
NotifyCallback del4 = name => { Console.WriteLine($"Notification received for: {name}"); };
Weitere Informationen finden Sie unter Lambdaausdrücke.
Im folgenden Beispiel wird verdeutlicht, wie Sie einen Delegaten deklarieren, instanziieren und verwenden. In der BookDB
-Klasse ist eine Buchhandlungsdatenbank gekapselt, die eine Buchtiteldatenbank enthält. Sie stellt eine ProcessPaperbackBooks
-Methode zur Verfügung, durch die alle Taschenbücher in der Datenbank gefunden werden und für jedes Taschenbuch ein Delegat aufgerufen wird. Der verwendete delegate
-Typ hat den Namen ProcessBookCallback
. Die Test
-Klasse verwendet diese Klasse, um die Buchtitel und Durchschnittspreise der Taschenbücher auszugeben.
Die Verwendung von Delegaten beinhaltet eine sinnvolle Trennung der Funktionalitäten von Buchhandlungsdatenbank und Clientcode. Der Clientcode hat keine Kenntnis darüber, wie die Bücher archiviert werden oder wie der Buchhandlungscode Taschenbücher sucht. Der Buchhandlungscode wiederum hat keine Kenntnis darüber, wie ein Taschenbuchtitel weiterverarbeitet wird, nachdem er gefunden wurde.
Beispiel
// 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
*/
Stabile Programmierung
Deklarieren von Delegaten
Mit der folgenden Anweisung wird ein neuer Delegattyp deklariert.
public delegate void ProcessBookCallback(Book book);
Durch die einzelnen Delegattypen werden Anzahl und Typen von Argumenten sowie Rückgabewerte von Methoden beschrieben, die gekapselt werden können. Sobald neue Argumenttypen benötigt werden oder ein neuer Rückgabewerttyp erforderlich ist, muss ein neuer Delegattyp deklariert werden.
Instanziieren von Delegaten
Nachdem ein Delegattyp deklariert wurde, muss ein Delegatobjekt erstellt und einer bestimmten Methode zugeordnet werden. Im vorherigen Beispiel übergeben Sie dazu die
PrintTitle
-Methode an dieProcessPaperbackBooks
-Methode, wie im folgenden Beispiel gezeigt:bookDB.ProcessPaperbackBooks(PrintTitle);
Hierdurch wird ein neues Delegatobjekt erstellt, das der statischen Methode
Test.PrintTitle
zugeordnet ist. Auf ähnliche Weise wird die nicht statische MethodeAddBookToTotal
für das Objekttotaller
übergeben, wie im folgenden Beispiel gezeigt:bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);
In beiden Fällen wird ein neues Delegatobjekt an die
ProcessPaperbackBooks
-Methode übergeben.Nach der Erstellung eines Delegaten wird die diesem zugeordnete Methode nicht mehr geändert. Delegatobjekte sind unveränderlich.
Aufrufen von Delegaten
Nachdem ein Delegatobjekt erstellt wurde, wird es normalerweise an anderen Code übergeben, durch den der Delegat aufgerufen wird. Ein Delegatobjekt wird über seinen Namen aufgerufen. Auf den Namen folgen (in Klammern gesetzte) Argumente, die an den Delegaten übergeben werden sollen. Es folgt ein Beispiel für einen Delegataufruf:
processBook(b);
Ein Delegat kann entweder (wie in diesem Beispiel) synchron oder mithilfe der
BeginInvoke
-Methode und derEndInvoke
-Methode asynchron aufgerufen werden.