Delegates Tutorial: Sample Files
Delegates Tutorial: Sample Files
Delegates Tutorial: Sample Files
This tutorial demonstrates the delegate types. It shows how to map delegates to static and
instance methods, and how to combine them (multicast).
Sample Files
See Delegates Sample to download and build the sample files discussed in this tutorial.
Further Reading
delegate
15. Delegates
Events Tutorial
Asynchronous Delegates
Tutorial
A delegate declaration defines a type that encapsulates a method with a particular set of
arguments and return type. For static methods, a delegate object encapsulates the method to be
called. For instance methods, a delegate object encapsulates both an instance and a method on
the instance. If you have a delegate object and an appropriate set of arguments, you can invoke
the delegate with the arguments.
An interesting and useful property of a delegate is that it does not know or care about the class of
the object that it references. Any object will do; all that matters is that the method's argument
types and return type match the delegate's. This makes delegates perfectly suited for
"anonymous" invocation.
Note Delegates run under the caller's security permissions, not the declarer's permissions.
Example 1
The following example illustrates declaring, instantiating, and using a delegate. The BookDB
class encapsulates a bookstore database that maintains a database of books. It exposes a method
ProcessPaperbackBooks, which finds all paperback books in the database and calls a delegate
for each one. The delegate type used is called ProcessBookDelegate. The Test class uses this
class to print out 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 done on the paperback books after it finds them.
Copy
// bookstore.cs
using System;
Output
Copy
Code Discussion
Copy
Instantiating a delegate Once a delegate type has been declared, a delegate object must be
created and associated with a particular method. Like all other objects, a new delegate object is
created with a new expression. When creating a delegate, however, the argument passed to the
new expression is special — it is written like a method call, but without the arguments to the
method.
Copy
bookDB.ProcessPaperbackBooks(new ProcessBookDelegate(PrintTitle));
creates a new delegate object associated with the static method Test.PrintTitle. The
following statement:
Copy
bookDB.ProcessPaperbackBooks(new
ProcessBookDelegate(totaller.AddBookToTotal));
creates a new delegate object associated with the nonstatic method AddBookToTotal on
the object totaller. In both cases, this new delegate object is immediately passed to the
ProcessPaperbackBooks method.
Note that once a delegate is created, the method it is associated with never changes —
delegate objects are immutable.
Calling a delegate Once 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. An
example of a delegate call is:
Copy
processBook(b);
This example demonstrates composing delegates. A useful property of delegate objects is that
they can be composed using the "+" operator. A composed delegate calls the two delegates it was
composed from. Only delegates of the same type can be composed.
The "-" operator can be used to remove a component delegate from a composed delegate.
Copy
// compose.cs
using System;
class MyClass
{
public static void Hello(string s)
{
Console.WriteLine(" Hello, {0}!", s);
}
Invoking delegate a:
Hello, A!
Invoking delegate b:
Goodbye, B!
Invoking delegate c:
Hello, C!
Goodbye, C!
Invoking delegate d:
Goodbye, D!
Delegates are ideally suited for use as events — notifications from one component to "listeners"
about changes in that component. For more information on the use of delegates for events, see
the Events Tutorial.
Delegates and interfaces are similar in that they enable the separation of specification and
implementation. Multiple independent authors can produce implementations that are compatible
with an interface specification. Similarly, a delegate specifies the signature of a method, and
authors can write methods that are compatible with the delegate specification. When should you
use interfaces, and when should you use delegates?
An event in C# is a way for a class to provide notifications to clients of that class when some
interesting thing happens to an object. The most familiar use for events is in graphical user
interfaces; typically, the classes that represent controls in the interface have events that are
notified when the user does something to the control (for example, click a button).
Events, however, need not be used only for graphical interfaces. Events provide a generally
useful way for objects to signal state changes that may be useful to clients of that object. Events
are an important building block for creating classes that can be reused in a large number of
different programs.
Events are declared using delegates. If you have not yet studied the Delegates Tutorial, you
should do so before continuing. Recall that a delegate object encapsulates a method so that it can
be called anonymously. An event is a way for a class to allow clients to give it delegates to
methods that should be called when the event occurs. When the event occurs, the delegate(s)
given to it by its clients are invoked.
In addition to the examples on declaring, invoking, and hooking up to events, this tutorial also
introduces the following topics: