Delegates And Events

  • July 2020
  • PDF

This document was uploaded by user and they confirmed that they have the permission to share it. If you are author or own the copyright of this book, please report to us by using this DMCA report form. Report DMCA


Overview

Download & View Delegates And Events as PDF for free.

More details

  • Words: 1,482
  • Pages: 8
C# Delegates and Events A delegate is a type that refers to a static method or an instance method.

A delegate is a .NET class that encapsulates a method, but not in the same way other classes encapsulate methods. A delegate actually stores the address of a method that is contained in some other class. So, a delegate is really the equivalent of a function pointer in C++. However, they are also far more than that. In this article, I explain the many uses of delegates. I begin with a simple example using a delegate to invoke a method. Then, I show several other uses of delegates including multicast delegates, thread delegates, anonymous methods, asynchronous method calls, events, and Win32 callbacks.

Declaring and using delegates You declare a delegate in a class or namespace using the delegate keyword and by specifying the signature of the method it will call. The following line declares a delegate named

GreetingDelegate which will reference a method that returns void and accepts a string as the argument.

delegate void GreetingDelegate(string s);

Now that we have declared the GreetingDelegate, we can instantiate it to encapsulate a method of that signature. Then, we can invoke the method through the delegate, just as if we invoked the method itself. The next code sample creates an instance of GreetingDelegate and uses it to invoke the

SendGreeting method. class DelegateDemo1 { static void Main(string[] args) { GreetingDelegate gd = new GreetingDelegate(SendGreeting); gd("Hello"); } static void SendGreeting(string s) { Console.WriteLine(s); } }

The DelegateDemo1 class shown above contains a static method named SendGreeting which has the same signature as the GreetingDelegate defined earlier. The Main method instantiates the GreetingDelegate, passing the SendGreeting method as argument. Next, Main invokes the SendingGreeting method through the delegate instance, passing the string “Hello”. Delegates only depend on the signature of the method, not on the class or object containing the method. Although the SendGreeting method above was declared as static, this is not a requirement. A delegate can reference an instance method as well. The next example uses the same

GreetingDelegate defined earlier to invoke an instance method. class Greeting { public void SendGreeting(string s) { Console.WriteLine(s); } } class DelegateDemo1 { static void Main(string[] args) { Greeting gr = new Greeting(); GreetingDelegate gd = new GreetingDelegate(gr.SendGreeting); gd ("Hello"); } }

This example defines a Greeting class that contains a single method named SendGreeting. Because its signature matches that of the GreetingDelegate, the method can be invoked through our delegate. In this example, the Main method first instantiates the Greeting class. Then, it creates an instance of GreetingDelegate, passing the Greeting object’s SendGreeting method as argument. Finally, Main calls the object’s SendGreeting method by invoking the delegate.

Multicast delegates As I said in the introduction, delegates do far more than provide an indirect way to call a method. They also contain an internal list of delegates—called the invocation list—which contains delegates of the same method signature. Whenever the delegate is invoked, it also invokes each delegate in its invocation list. You add and remove delegates from an invocation list using the overloaded += and -= operators. The next example defines two methods of the correct signature for our GreetingDelegate and calls them both through a single call to an instance of the GreetingDelegate.

class Greeting { public void SendGreeting(string s) { Console.WriteLine(s); } public void SendGreetingToFile(string s) { StreamWriter writer = new StreamWriter(@"c:\greeting.txt"); writer.WriteLine(s); writer.Close(); } } class DelegateDemo1 { static void Main(string[] args) { // create the Greeting object Greeting gr = new Greeting(); // create the delegates GreetingDelegate gd = new GreetingDelegate(gr.SendGreeting); gd += new GreetingDelegate(gr.SendGreetingToFile); // invoke both methods through the delegate gd("Hello"); } }

In this example, we have added a second method to the Greeting class. The

SendGreetingToFile method does exactly as its name suggests. It creates a StreamWriter instance and uses it to log the string argument to a file named "greeting.txt". This time, after creating the GreetingDelegate, the Main method instantiates a second

GreetingDelegate and appends it to the first instances’ invocation list through the += operator. When the last line of Main calls the delegate, both methods are invoked with the string “Hello”. So far, we have seen delegates used to call methods of other classes and objects. But, as I have already said, that is only the beginning. The fact that they can be bound to methods of any class or object gives them great utility. Delegates are central to .NET, as they are used in threads, events, and asynchronous programming. Now that we have seen how to create and use delegates, let’s take a look at some of their applications.

Thread delegates

Multithreaded programming in .NET is implemented through the use of delegates. The .NET Framework defines the ThreadStart delegate to invoke a method in a separate thread. The

Thread class, defined in the System.Threading namespace, accepts an instance of the ThreadStart delegate as its constructor argument. When you call the Thread object’s Start method, that Thread object will invoke the delegate in its own thread of execution. The following example demonstrates this by calling a method named ThreadProc in a separate thread.

static void ThreadProc() { // do some thread work CalculatePrimes(); } static void Main(string[] args) { Thread t = new Thread(new ThreadStart(ThreadProc)); t.Start(); t.Join(); }

In this example, the Main method creates a Thread object, passing a new ThreadStart delegate to its constructor. That ThreadStart delegate stores a reference to the ThreadProc method. Then, Main calls the Thread object’s Start method which causes its delegate to begin execution in a separate thread. The final line of Main is a call to the Thread object’s Join method, which causes

Main to block, waiting for the thread’s delegated method call to return

Events The Event model in C# finds its roots in the event programming model that is popular in asynchronous programming. The basic foundation behind this programming model is the idea of "publisher and subscribers." In this model, you have publishers who will do some logic and publish an "event." Publishers will then send out their event only to subscribers who have subscribed to receive the specific event. In C#, any object can publish a set of events to which other applications can subscribe. When the publishing class raises an event, all the subscribed applications are notified. The following figure shows this mechanism.

Conventions The following important conventions are used with events: Event Handlers in the .NET Framework return void and take two parameters. The first paramter is the source of the event; that is the publishing object. The second parameter is an object derived from EventArgs. Events are properties of the class publishing the event. The keyword event controls how the event property is accessed by the subscribing classes.

Simple Event Let's modify our logging example from above to use an event rather than a delegate: using System; using System.IO;

namespace Akadia.SimpleEvent { /* ========= Publisher of the Event ============== */ public class MyClass { // Define a delegate named LogHandler, which will encapsulate // any method that takes a string as the parameter and returns no value public delegate void LogHandler(string message); // Define an Event based on the above Delegate public event LogHandler Log; // Instead of having the Process() function take a delegate // as a parameter, we've declared a Log event. Call the Event, // using the OnXXXX Method, where XXXX is the name of the Event. public void Process() { OnLog("Process() begin"); OnLog("Process() end"); } // By Default, create an OnXXXX Method, to call the Event protected void OnLog(string message) { if (Log != null) { Log(message); } } } // The FileLogger class merely encapsulates the file I/O public class FileLogger { FileStream fileStream; StreamWriter streamWriter; // Constructor public FileLogger(string filename) { fileStream = new FileStream(filename, FileMode.Create); streamWriter = new StreamWriter(fileStream); } // Member Function which is used in the Delegate public void Logger(string s) { streamWriter.WriteLine(s); } public void Close() { streamWriter.Close(); fileStream.Close(); }

} /* ========= Subscriber of the Event ============== */ // It's now easier and cleaner to merely add instances // of the delegate to the event, instead of having to // manage things ourselves public class TestApplication { static void Logger(string s) { Console.WriteLine(s); } static void Main(string[] args) { FileLogger fl = new FileLogger("process.log"); MyClass myClass = new MyClass(); // Subscribe the Functions Logger and fl.Logger myClass.Log += new MyClass.LogHandler(Logger); myClass.Log += new MyClass.LogHandler(fl.Logger); // The Event will now be triggered in the Process() Method myClass.Process(); fl.Close(); } } } Compile an test: # csc SimpleEvent.cs # SimpleEvent.exe Process() begin Process() end # cat process.log Process() begin Process() end

More useful links to see. http://msdn.microsoft.com/en-us/library/900fyy8e(VS.71).aspx (Delegates) http://msdn.microsoft.com/en-us/library/8627sbea(VS.71).aspx (Events) http://msdn.microsoft.com/en-us/library/17sde2xt(VS.71).aspx (Delegates & Events) http://msdn.microsoft.com/en-us/library/system.delegate(VS.71).aspx (Raising an Event) http://msdn.microsoft.com/en-us/library/2ccyd347(VS.71).aspx (Consuming an Event) http://msdn.microsoft.com/en-us/vcsharp/bb508935.aspx (Multicast Delegate Internals)

http://www.dotnetjohn.com/articles.aspx?articleid=262 (Working with Delegates Delegates in C#) http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=18 (Delegates and Events - The Uncensored Story) http://www.akadia.com/services/dotnet_delegates_and_events.html http://en.csharp-online.net/CSharp_Delegates_and_Events http://www.aspfree.com/c/a/C-Sharp/C-Sharp-Delegates-Explained/

Related Documents