C # Delegate
Delegate
Definition: [Modifier] DeleGate <return type> <delegate Name> ([parameter 1, parameter 2…]);
A delegate is a type of reference method. Once a method is assigned to the Delegate, the delegate has the same behavior as the delegate. The use of delegate methods can have parameters and return values like any other method, as shown in the following example.
public delegate int PerformCalculation(int x, int y);
Delegation has the following features:
The delegate is similar to a C ++ function pointer, but it is type-safe.
The delegate allows passing methods as parameters.
A delegate can be used to define a callback method.
The delegate can be linked together. For example, multiple methods can be called for an event.
The method does not need to be exactly matched with the delegate signature. For more information, see covariant and inverter.
C #2.0 introduces the concept of anonymous methods, which allow passing code blocks as parameters instead of Individually Defined methods.
The delegate type is sealed.
When constructing a delegate object, the name of the Delegate-wrapped method is usually provided or the anonymous method is used. After the delegate is instantiated, the Delegate will pass the method calls to it to the method. The parameters passed by the caller to the delegate are passed to the method. The return values (if any) from the method are returned by the delegate to the caller. This is called a call delegate. An instantiated delegate can be called as the wrapped method itself.
// 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");
The delegate type cannot be derived from delegate, or a custom class cannot be derived from it. Because the instantiation delegate is an object, it can be passed as a parameter or assigned to the attribute. In this way, a delegate can be accepted as a parameter and can be called later. This is called asynchronous callback. It is a common method used to notify the caller after a long process is completed. When using a delegate in this way, the code that uses the delegate does not need to know any information about the implementation of the method used. This function is similar to the encapsulation provided by the interface.
When to use delegation instead of using interfaces
Reference: MS-help: // Ms. VSCC. v80/ms. msdn. v80/ms. visualstudio. v80.chs/dv_csref/html/2e759bdf-7ca4-4005-8597-af92edf6d8f0.htm
Delegate naming method MS-help: // Ms. VSCC. v80/ms. msdn. v80/ms. visualstudio. v80.chs/dv_csref/html/97de039b-c76b-4b9c-a27d-8c1e1c8d93da.htm
Mutual variables and inverters in the delegate
When the delegate method matches the delegate signature, the covariant and inverter provide a certain degree of flexibility. The covariant allows you to use methods with derived return types as delegates, and the inverter allows you to use methods with derived parameters as delegates. This makes the creation of delegate methods more flexible and can process multiple specific classes or events.
Covariant
When the return type of the delegate method has a greater degree of derivation than the delegate signature, it is called the co-variant delegate method. Because the return type of a method is more specific than the return type of the delegate signature, implicit conversion can be performed on it. This method can be used as a delegate.
Covariant makes it possible to create a delegate method that can be used by both the class and the derived class.
This example shows how to use a derived return type for a delegate.SecondHandlerThe returned data type isDogsType, which is the return type of the delegate SignatureMammals. Therefore,SecondHandlerAll possible values returned can be stored inMammalsType variable.
class Mammals{}class Dogs : Mammals{}class Program{ // Define the delegate. public delegate Mammals HandlerMethod(); public static Mammals FirstHandler() { return null; } public static Dogs SecondHandler() { return null; } static void Main() { HandlerMethod handler1 = FirstHandler; // Covariance allows this delegate. HandlerMethod handler2 = SecondHandler; }}
Inverter
When the delegate method signature has one or more parameters and the types of these parameters are derived from the type of the method parameter, it is called the inverse delegate method. Because the signature parameters of the delegate method are more specific than the method parameters, they can be implicitly converted when passed to the handler method.
In this way, the inverter makes it easier to create a more common delegate method that can be used by a large number of classes.
class Mammals { }class Dogs : Mammals { }class Program{ public delegate void HandlerMethod(Dogs sampleDog); public static void FirstHandler(Mammals elephant) { } public static void SecondHandler(Dogs sheepDog) { } static void Main(string[] args) { // Contravariance permits this delegate. HandlerMethod handler1 = FirstHandler; HandlerMethod handler2 = SecondHandler; }}
Merge delegate (multi-channel broadcast delegate)
delegate void Del(string s);class TestClass{ static void Hello(string s) { System.Console.WriteLine(" Hello, {0}!", s); } static void Goodbye(string s) { System.Console.WriteLine(" Goodbye, {0}!", s); } static void Main() { Del a, b, c, d; // Create the delegate object a that references // the method Hello: a = Hello; // Create the delegate object b that references // the method Goodbye: b = Goodbye; // The two delegates, a and b, are composed to form c: c = a + b; // Remove a from the composed delegate, leaving d, // which calls only the method Goodbye: d = c - a; System.Console.WriteLine("Invoking delegate a:"); a("A"); System.Console.WriteLine("Invoking delegate b:"); b("B"); System.Console.WriteLine("Invoking delegate c:"); c("C"); System.Console.WriteLine("Invoking delegate d:"); d("D"); }}
Above output
Invoking delegate a: Hello, A!Invoking delegate b: Goodbye, B!Invoking delegate c: Hello, C! Goodbye, C!Invoking delegate d: Goodbye, D!
Declare, instantiate, and use Delegation
Delegate statement
public delegate void Del<T>(T item);public void Notify(int i) { }
Or
Del<int> d1 = new Del<int>(Notify);
Or
Del<int> d2 = Notify;
The following example illustrates the declaration, instantiation, and use of delegation.BookDBClass encapsulates a bookstore database, which maintains a Book database. It is publicProcessPaperbackBooksThis method searches for all the books in the database and calls a delegate for each book. The delegate type used is calledProcessBookDelegate.TestClass uses this class to output the title and average price of the books.
The use of delegation promotes a good separation of functions between the bookstore database and customer code.. The Customer Code does not know how books are stored or how the bookstore code looks for books on a regular basis. The bookstore Code does not know what to do with the book after it finds it.
// 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); } }}
Above output
Paperback Book Titles: The C Programming Language The Unicode Standard 2.0 Dogbert's Clues for the CluelessAverage Paperback Book Price: $23.97