{"id":2598,"date":"2017-06-08T17:30:20","date_gmt":"2017-06-08T16:30:20","guid":{"rendered":"http:\/\/www.nivas.hr\/blog\/?p=2598"},"modified":"2017-06-08T17:30:20","modified_gmt":"2017-06-08T16:30:20","slug":"csharp-delegates-and-events","status":"publish","type":"post","link":"https:\/\/www.nivas.hr\/blog\/2017\/06\/08\/csharp-delegates-and-events\/","title":{"rendered":"C# Delegates and Events"},"content":{"rendered":"<p>When I started learning C# the difference and relation between delegate and event was not so clear to me. After checking few books and lots of googling I realized that I am not the only one. :)<\/p>\n<p>Some resources were correct in their description but lacked the comprehensive examples, other were completely wrong or just very unclear.<\/p>\n<p>In this article the same task will be implemented using only delegate, and then using both delegate and event. So the difference, relation between delegate and event and the advantage of using the event will be clear.<\/p>\n<p>It is expected that reader of this article is familiar with basic C# and has <em>some<\/em> knowledge about delegates and events.<\/p>\n<h2>Delegate<\/h2>\n<blockquote><p>A delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature and return type. You can invoke (or call) the method through the delegate instance.<\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/programming-guide\/delegates\/\">https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/programming-guide\/delegates\/<\/a><\/p><\/blockquote>\n<p>Please note that delegates can be chained \u2013 on single call multiple methods will be called.<\/p>\n<h2>Event<\/h2>\n<blockquote><p>Events enable a class or object to notify other classes or objects when something of interest occurs. The class that sends (or raises) the event is called the publisher and the classes that receive (or handle) the event are called subscribers.<\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/programming-guide\/events\/\">https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/programming-guide\/events\/<\/a><\/p><\/blockquote>\n<h2>Task<\/h2>\n<p>We will create one lemming and three watchers that will monitor its health and respond as soon as health changes.<\/p>\n<h2>Delegate example<\/h2>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace delegate_only\r\n{\r\n\tpublic delegate void LemmingChanged(Lemming lemming);\r\n\r\n\tpublic class Lemming\r\n\t{\r\n\t\tprivate int health;\r\n\r\n\t\tpublic int Health\r\n\t\t{\r\n\t\t\tget { return health; }\r\n\t\t\tset\r\n\t\t\t{\r\n\t\t\t\thealth = value;\r\n\r\n\t\t\t\tif (LemmingChanged != null)\r\n\t\t\t\t{\r\n\t\t\t\t\tLemmingChanged(this);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic LemmingChanged LemmingChanged;\r\n\t}\r\n\r\n\tclass LemmingWatch\r\n\t{\r\n\t\tpublic void LemmingChangedHandler(Lemming lemming)\r\n\t\t{\r\n\t\t\tConsole.WriteLine($&quot;LemmingWatch lemming changed. Health=({lemming.Health})&quot;);\r\n\t\t}\r\n\t}\r\n\r\n\tclass AnotherLemmingWatch\r\n\t{\r\n\t\tpublic void LemmingChangedHandler(Lemming Lemming)\r\n\t\t{\r\n\t\t\tConsole.WriteLine($&quot;AnotherLemmingWatch Lemming changed. Health=({Lemming.Health})&quot;);\r\n\t\t}\r\n\t}\r\n\r\n\tclass YetAnotherLemmingWatch\r\n\t{\r\n\t\tpublic void LemmingChangedHandler(Lemming Lemming)\r\n\t\t{\r\n\t\t\tConsole.WriteLine($&quot;YetAnotherLemmingWatch Lemming changed. Health=({Lemming.Health})&quot;);\r\n\t\t}\r\n\t}\r\n\r\n\tclass Program\r\n\t{\r\n\t\tstatic void Main(string[] args)\r\n\t\t{\r\n\t\t\tLemming Lemming = new Lemming() { Health = 99 };\r\n\r\n\t\t\tLemmingWatch LemmingWatch = new LemmingWatch();\r\n\t\t\tAnotherLemmingWatch anotherLemmingWatch = new AnotherLemmingWatch();\r\n\r\n\t\t\tLemming.LemmingChanged += LemmingWatch.LemmingChangedHandler;\r\n\t\t\tLemming.LemmingChanged += anotherLemmingWatch.LemmingChangedHandler;\r\n\r\n\t\t\tConsole.WriteLine(&quot;Change Health:&quot;);\r\n\t\t\tLemming.Health = 80;\r\n\r\n\t\t\tConsole.WriteLine(&quot;\\n--\\n&quot;);\r\n\r\n\t\t\t\/\/ LemmingChanged not encapsulated \r\n\t\t\tConsole.WriteLine(&quot;LemmingChanged not encapsuled: Loose previous chained methods by mistake:&quot;);\r\n\r\n\t\t\tYetAnotherLemmingWatch yetAnotherLemmingWatching = new YetAnotherLemmingWatch();\r\n\t\t\tLemming.LemmingChanged = yetAnotherLemmingWatching.LemmingChangedHandler; \/\/ loosing previous chained methods - mistake '=' instead of '+='\r\n\t\t\tConsole.WriteLine(&quot;Change Health:&quot;);\r\n\t\t\tLemming.Health = 51;\r\n\t\t\t\r\n\r\n\t\t\tConsole.ReadLine();\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<h3>Output<\/h3>\n<pre>Change Health:\r\nLemmingWatch lemming changed. Health=(80)\r\nAnotherLemmingWatch Lemming changed. Health=(80)\r\n\r\n--\r\n\r\nLemmingChanged not encapsuled: Loose previous chained methods by mistake:\r\nChange Health:\r\nYetAnotherLemmingWatch Lemming changed. Health=(51)<\/pre>\n<p>As you can see delegate is public \u2013 for now, this is necessary in order to enable adding event handler from outside of the class.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic LemmingChanged LemmingChanged;\r\n<\/pre>\n<p>Two event handlers are successfully added:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nLemming.LemmingChanged += LemmingWatch.LemmingChangedHandler;\r\nLemming.LemmingChanged += anotherLemmingWatch.LemmingChangedHandler;\r\n<\/pre>\n<p>But there is mistake when adding the third one \u2013 and two previously added event handlers are removed by simple typing mistake (= instead of +=):<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nLemming.LemmingChanged = yetAnotherLemmingWatching.LemmingChangedHandler;\r\n<\/pre>\n<p>Also since delegate is public \u2013 it is possible to evoke the event from the outside of the class and evoke event handlers although requirements for raising the event are not met.<\/p>\n<h2>Event example<\/h2>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nnamespace delegate_with_event\r\n{\r\n\tpublic delegate void LemmingChanged(Lemming lemming);\r\n\r\n\tpublic class Lemming\r\n\t{\r\n\t\tprivate int health;\r\n\r\n\t\tpublic int Health\r\n\t\t{\r\n\t\t\tget { return health; }\r\n\t\t\tset\r\n\t\t\t{\r\n\t\t\t\thealth = value;\r\n\r\n\t\t\t\tif (lemmingChanged != null)\r\n\t\t\t\t{\r\n\t\t\t\t\tlemmingChanged(this); \/\/ use private delegate\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate LemmingChanged lemmingChanged; \/\/ changed to private\r\n\r\n\t\t\/\/ use event to add and remove event handler to\/from delegate\r\n\t\tpublic event LemmingChanged LemmingChanged\r\n\t\t{\r\n\t\t\tadd\r\n\t\t\t{\r\n\t\t\t\tlemmingChanged += value;\r\n\t\t\t}\r\n\t\t\tremove\r\n\t\t\t{\r\n\t\t\t\tlemmingChanged -= value;\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\r\n\t}\r\n\r\n\tclass LemmingWatch\r\n\t{\r\n\t\tpublic void LemmingChangedHandler(Lemming lemming)\r\n\t\t{\r\n\t\t\tConsole.WriteLine($&quot;LemmingWatch lemming changed. Health=({lemming.Health})&quot;);\r\n\t\t}\r\n\t}\r\n\r\n\tclass AnotherLemmingWatch\r\n\t{\r\n\t\tpublic void LemmingChangedHandler(Lemming Lemming)\r\n\t\t{\r\n\t\t\tConsole.WriteLine($&quot;AnotherLemmingWatch Lemming changed. Health=({Lemming.Health})&quot;);\r\n\t\t}\r\n\t}\r\n\r\n\tclass YetAnotherLemmingWatch\r\n\t{\r\n\t\tpublic void LemmingChangedHandler(Lemming Lemming)\r\n\t\t{\r\n\t\t\tConsole.WriteLine($&quot;YetAnotherLemmingWatch Lemming changed. Health=({Lemming.Health})&quot;);\r\n\t\t}\r\n\t}\r\n\r\n\tclass Program\r\n\t{\r\n\t\tstatic void Main(string[] args)\r\n\t\t{\r\n\t\t\tLemming Lemming = new Lemming() { Health = 99 };\r\n\r\n\t\t\tLemmingWatch LemmingWatch = new LemmingWatch();\r\n\t\t\tAnotherLemmingWatch anotherLemmingWatch = new AnotherLemmingWatch();\r\n\r\n\t\t\tLemming.LemmingChanged += LemmingWatch.LemmingChangedHandler;\r\n\t\t\tLemming.LemmingChanged += anotherLemmingWatch.LemmingChangedHandler;\r\n\r\n\t\t\tConsole.WriteLine(&quot;Change Health:&quot;);\r\n\t\t\tLemming.Health = 80;\r\n\r\n\t\t\tConsole.WriteLine(&quot;\\n--\\n&quot;);\r\n\r\n\t\t\t\/\/ LemmingChanged not encapsulated \r\n\t\t\tConsole.WriteLine(&quot;Add 3rd event handler:&quot;);\r\n\r\n\t\t\tYetAnotherLemmingWatch yetAnotherLemmingWatching = new YetAnotherLemmingWatch();\r\n\t\t\t\/\/ impossible to make mistake: C# error: event Lemming.LemmingChanged can only appear on the left hand side of += -=\r\n\t\t\t\/\/Lemming.LemmingChanged = yetAnotherLemmingWatching.LemmingChangedHandler; \r\n\t\t\tLemming.LemmingChanged += yetAnotherLemmingWatching.LemmingChangedHandler;\r\n\t\t\tConsole.WriteLine(&quot;Change Health:&quot;);\r\n\t\t\tLemming.Health = 51;\r\n\r\n\r\n\t\t\tConsole.ReadLine();\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<h3>Output<\/h3>\n<pre> Change Health:\r\n LemmingWatch lemming changed. Health=(80)\r\n AnotherLemmingWatch Lemming changed. Health=(80)\r\n\r\n--\r\n\r\nAdd 3rd event handler:\r\n Change Health:\r\n LemmingWatch lemming changed. Health=(51)\r\n AnotherLemmingWatch Lemming changed. Health=(51)\r\n YetAnotherLemmingWatch Lemming changed. Health=(51)<\/pre>\n<p>Delegate is now private:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate LemmingChanged lemmingChanged;\r\n<\/pre>\n<p>Using event to add or remove event handler to or from delegate is very similar as using properties to get and set value to member variables.<\/p>\n<p>Just instead of set\/get,\u00a0 add\/remove is used. :)<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic event LemmingChanged LemmingChanged\r\n{\r\n\tadd\r\n\t{\r\n\t\tlemmingChanged += value;\r\n\t}\r\n\tremove\r\n\t{\r\n\t\tlemmingChanged -= value;\r\n\t}\r\n}\r\n<\/pre>\n<p>Adding and removing the event handlers is done through event. It is not possible to access delegate directly from outside of the class.<\/p>\n<p>And if we try to clear previously added event handlers by using = instead of += as in previous example &#8211; it is just not possible:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nLemming.LemmingChanged = yetAnotherLemmingWatching.LemmingChangedHandler; \r\n<\/pre>\n<p>C# will report error:<\/p>\n<blockquote><p>event Lemming.LemmingChanged can only appear on the left hand side of += -=<\/p><\/blockquote>\n<h2>Conclusion<\/h2>\n<p>Events are heavily relay on delegates. In fact relationship between events and delegates is very similar as relationship between properties and member variables. Events provide safe and friendly way of using delegates.<\/p>\n<p>They enable adding and removing event handlers from the outside of the class without allowing bad things to happen. Using events it is not possible to clear all event handlers by mistake or to raise the event from outside of the class (this is important because it is class responsibility to invoke the delegate when some class internal conditions are met).<\/p>\n<p>By using events as a &#8220;wrapper&#8221; for delegate you encapsulation is not broken and you keep the needed flexibility. You can have you cake an eat it. :)<br \/>\n<a href=\"http:\/\/www.nivas.hr\/blog\/wp-content\/uploads\/2017\/06\/kolac.jpg\"><img loading=\"lazy\" class=\"aligncenter wp-image-2629\" src=\"http:\/\/www.nivas.hr\/blog\/wp-content\/uploads\/2017\/06\/kolac-450x194.jpg\" alt=\"\" width=\"517\" height=\"223\" srcset=\"https:\/\/www.nivas.hr\/blog\/wp-content\/uploads\/2017\/06\/kolac-450x194.jpg 450w, https:\/\/www.nivas.hr\/blog\/wp-content\/uploads\/2017\/06\/kolac-768x331.jpg 768w, https:\/\/www.nivas.hr\/blog\/wp-content\/uploads\/2017\/06\/kolac.jpg 999w\" sizes=\"(max-width: 517px) 100vw, 517px\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>When I started learning C# the difference and relation between delegate and event was not so clear to me. After checking few books and lots of googling I realized that I am not the only one. :) Some resources were correct in their description but lacked the comprehensive examples, other were completely wrong or just&#8230;<\/p>\n","protected":false},"author":6,"featured_media":2621,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[53,1],"tags":[54,55,56,59,57,58],"_links":{"self":[{"href":"https:\/\/www.nivas.hr\/blog\/wp-json\/wp\/v2\/posts\/2598"}],"collection":[{"href":"https:\/\/www.nivas.hr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.nivas.hr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.nivas.hr\/blog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/www.nivas.hr\/blog\/wp-json\/wp\/v2\/comments?post=2598"}],"version-history":[{"count":31,"href":"https:\/\/www.nivas.hr\/blog\/wp-json\/wp\/v2\/posts\/2598\/revisions"}],"predecessor-version":[{"id":2632,"href":"https:\/\/www.nivas.hr\/blog\/wp-json\/wp\/v2\/posts\/2598\/revisions\/2632"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.nivas.hr\/blog\/wp-json\/wp\/v2\/media\/2621"}],"wp:attachment":[{"href":"https:\/\/www.nivas.hr\/blog\/wp-json\/wp\/v2\/media?parent=2598"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.nivas.hr\/blog\/wp-json\/wp\/v2\/categories?post=2598"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.nivas.hr\/blog\/wp-json\/wp\/v2\/tags?post=2598"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}