# C# Study - Delegate ###### tags: `C#` `Study` `Delegate` # [C# - Delegates](https://www.tutorialsteacher.com/csharp/csharp-delegates) What if we want to __pass a function as a parameter__? How does C# handles the __callback functions or event handler__? The answer is - delegate. The delegate is a __reference type data type__ that defines the method signature. You can define variables of delegate, just like other data type, that can refer to any method with the same signature as the delegate. There are three steps involved while working with delegates: 1. Declare a delegate 2. Set a target method 3. Invoke a delegate ## Declare a Delegate A delegate can be declared using the ``delegate`` keyword followed by ``a function signature``, as shown below. ``` [access modifier] delegate [return type] [delegate name]([parameters]) ``` Example: Declare a Delegate: ``` public delegate void MyDelegate(string msg); ``` Above, we have declared a delegate ``MyDelegate`` with a ``void`` return type and a ``string`` parameter. __A delegate can be declared outside of the class or inside the class. Practically, it should be declared out of the class__. After declaring a delegate, we need to __set the target method or a lambda expression__. We can do it __by creating an object of the delegate using the ``new`` keyword and passing a method whose signature matches the delegate signature__. Example: Set Delegate Target: ``` public delegate void MyDelegate(string msg); // declare a delegate // set target method MyDelegate del = new MyDelegate(MethodA); // or MyDelegate del = MethodA; // or set lambda expression MyDelegate del = (string msg) => Console.WriteLine(msg); // target method static void MethodA(string message) { Console.WriteLine(message); } ``` 可以 new 自己宣告的 delegate 或直接 aasign 某一個 method 或 接上 lambda expression You can set the target method __by assigning a method directly without creating an object of delegate__ e.g., ``MyDelegate del = MethodA``. ## Invoke a Delegate After setting a target method, a delegate can be invoked using the ``Invoke()`` method or using the ``()`` operator. Example: Invoke a Delegate: ``` del.Invoke("Hello World!"); // or del("Hello World!"); ``` The following is a full example of a delegate. ``` public delegate void MyDelegate(string msg); //declaring a delegate class Program { static void Main(string[] args) { MyDelegate del = ClassA.MethodA; del("Hello World"); del = ClassB.MethodB; del("Hello World"); del = (string msg) => Console.WriteLine("Called lambda expression: " + msg); del("Hello World"); } } class ClassA { static void MethodA(string message) { Console.WriteLine("Called ClassA.MethodA() with parameter: " + message); } } class ClassB { static void MethodB(string message) { Console.WriteLine("Called ClassB.MethodB() with parameter: " + message); } } ``` ## Passing Delegate as a Parameter A method can have a parameter of the delegate type, as shown below. ``` public delegate void MyDelegate(string msg); //declaring a delegate class Program { static void Main(string[] args) { MyDelegate del = ClassA.MethodA; InvokeDelegate(del); del = ClassB.MethodB; InvokeDelegate(del); del = (string msg) => Console.WriteLine("Called lambda expression: " + msg); InvokeDelegate(del); } static void InvokeDelegate(MyDelegate del) // MyDelegate type parameter { del("Hello World"); } } class ClassA { static void MethodA(string message) { Console.WriteLine("Called ClassA.MethodA() with parameter: " + message); } } class ClassB { static void MethodB(string message) { Console.WriteLine("Called ClassB.MethodB() with parameter: " + message); } } ``` In .NET, ``Func`` and ``Action`` types are built-in generic delegates that should be used for most common delegates instead of creating new custom delegates. ## Multicast Delegate __The delegate can point to multiple methods__. A delegate that points multiple methods is called a __multicast delegate__. The ``+`` or ``+=`` operator adds a function to the invocation list, and the ``-`` and ``-=`` operator removes it. ``` public delegate void MyDelegate(string msg); //declaring a delegate class Program { static void Main(string[] args) { MyDelegate del1 = ClassA.MethodA; MyDelegate del2 = ClassB.MethodB; MyDelegate del = del1 + del2; // combines del1 + del2 del("Hello World"); MyDelegate del3 = (string msg) => Console.WriteLine("Called lambda expression: " + msg); del += del3; // combines del1 + del2 + del3 del("Hello World"); del = del - del2; // removes del2 del("Hello World"); del -= del1 // removes del1 del("Hello World"); } } class ClassA { static void MethodA(string message) { Console.WriteLine("Called ClassA.MethodA() with parameter: " + message); } } class ClassB { static void MethodB(string message) { Console.WriteLine("Called ClassB.MethodB() with parameter: " + message); } } ``` The addition and subtraction operators always work as part of the assignment: ``del1 += del2``; is exactly equivalent to ``del1 = del1+del2``; and likewise for subtraction. If a delegate __returns a value__, then the __last assigned target method's value will be return__ when a multicast delegate called. __Multicast Delegates, 若有回傳值,其回傳值是最後一個加入的 Delegate 所回傳的__ ### Example - Multicast Delegate Returning a Value: ``` public delegate int MyDelegate(); //declaring a delegate class Program { static void Main(string[] args) { MyDelegate del1 = ClassA.MethodA; MyDelegate del2 = ClassB.MethodB; MyDelegate del = del1 + del2; Console.WriteLine(del());// returns 200 } } class ClassA { static int MethodA() { return 100; } } class ClassB { static int MethodB() { return 200; } } ``` ## Generic Delegate A generic delegate can be defined the same way as a delegate but using generic type parameters or return type. The generic type must be specified when you set a target method. For example, consider the following generic delegate that is used for int and string parameters. ``` public delegate T add<T>(T param1, T param2); // generic delegate class Program { static void Main(string[] args) { add<int> sum = Sum; Console.WriteLine(sum(10, 20)); add<string> con = Concat; Console.WriteLine(conct("Hello ","World!!")); } public static int Sum(int val1, int val2) { return val1 + val2; } public static string Concat(string str1, string str2) { return str1 + str2; } } ``` Delegate is also used to declare an Event and an Anonymous Method. --- # [C# - Func Delegate](https://www.tutorialsteacher.com/csharp/csharp-func-delegate) C# includes __built-in generic delegate types__ ``Func`` and ``Action``, so that you don't need to define custom delegates manually in most cases. ``Func`` is a generic delegate included in the ``System`` namespace. It has __zero or more input parameters and one out parameter__. The last parameter is considered as an ``out`` parameter. The ``Func`` delegate that takes one input parameter and one out parameter is defined in the ``System`` namespace, as shown below: Signature: Func ``` namespace System { public delegate TResult Func<in T, out TResult>(T arg); } ``` The following ``Func`` delegate takes two input parameters of ``int`` type and returns a value of ``int`` type: ``` Func<int, int, int> sum; ``` You can assign any method to the above func delegate that takes two ``int`` parameters and returns an ``int`` value. ``` class Program { static int Sum(int x, int y) { return x + y; } static void Main(string[] args){ Func<int, int, int> add = Sum; int result = add(10, 10); Console.WriteLine(result); } } ``` A ``Func`` delegate type can include 0 to 16 input parameters of different types. However, it must include an ``out`` parameter for the result. For example, the following Func delegate doesn't have any input parameter, and it includes only an out parameter. ``` Func<int> getRandomNumber; ``` ## C# Func with an Anonymous Method You can assign an anonymous method to the Func delegate by using the delegate keyword. ``` Func<int> getRandomNumber = delegate() { Random rnd = new Random(); return rnd.Next(1, 100); }; ``` ## Func with Lambda Expression A ``Func`` delegate can also be used with a lambda expression, as shown below: ``` Func<int> getRandomNumber = () => new Random().Next(1, 100); //Or Func<int, int, int> Sum = (x, y) => x + y; ``` --- # [C# - Action Delegate](https://www.tutorialsteacher.com/csharp/csharp-action-delegate) Action is a delegate type defined in the ``System`` namespace. An Action type delegate is the same as ``Func`` delegate except that the __``Action`` delegate doesn't return a value__. In other words, an ‵Action‵ delegate can be used with a method that __has a ``void`` return type__. For example, the following delegate __prints an ``int`` value__. ``` public delegate void Print(int val); static void ConsolePrint(int i) { Console.WriteLine(i); } static void Main(string[] args) { Print printDel = ConsolePrint; printDel(10); } ``` You can __use an ``Action`` delegate instead of defining the above ``Print`` delegate__, for example: ### Example: Action delegate ``` static void ConsolePrint(int i) { Console.WriteLine(i); } static void Main(string[] args) { Action<int> printActionDel = ConsolePrint; printActionDel(10); } ``` You can initialize an Action delegate using the ``new`` keyword or by directly assigning a method: ``` Action<int> printActionDel = ConsolePrint; //Or Action<int> printActionDel = new Action<int>(ConsolePrint); ``` An ``Action`` delegate __can take up to 16 input parameters of different types__. > 和 ``Func`` 一樣 An __Anonymous method__ can also be assigned to an ``Action`` delegate, for example: ### Example: Anonymous method with ``Action`` delegate ``` static void Main(string[] args) { Action<int> printActionDel = delegate(int i) { Console.WriteLine(i); }; printActionDel(10); } ``` A __Lambda expression__ also can be used with an ``Action`` delegate: ### Example: Lambda expression with Action delegate ``` static void Main(string[] args) { Action<int> printActionDel = i => Console.WriteLine(i); printActionDel(10); } ``` Thus, you can use any method that doesn't return a value with ``Action`` delegate types. ## Advantages of ``Action`` and ``Func`` Delegates 1. Easy and quick to define delegates. 2. Makes code short. 3. Compatible type throughout the application. --- ### [Action Delegate](https://docs.microsoft.com/en-us/dotnet/api/system.action?view=netcore-3.1) Encapsulates a method that has no parameters and does not return a value. ``` public delegate void Action(); ``` Inheritance: ``Object`` <- ``Delegate`` <- ``Action`` --- ### [``Action<T>`` Delegate](https://docs.microsoft.com/en-us/dotnet/api/system.action-1?view=netcore-3.1) Encapsulates a method that has a single parameter and does not return a value. ``` public delegate void Action<in T>(T obj); ``` ### [``Action<T1,T2>`` Delegate](https://docs.microsoft.com/en-us/dotnet/api/system.action-2?view=netcore-3.1) Encapsulates a method that has two parameters and does not return a value. ``` public delegate void Action<in T1,in T2>(T1 arg1, T2 arg2); ``` --- # [C# - Predicate Delegate](https://www.tutorialsteacher.com/csharp/csharp-predicate) ### [``Predicate<T>`` Delegate](https://docs.microsoft.com/en-us/dotnet/api/system.predicate-1?view=netcore-3.1) Represents the method that defines a set of criteria and determines whether the specified object meets those criteria. ``` public delegate bool Predicate<in T>(T obj); ``` ``Predicate`` is the delegate like ``Func`` and ``Action`` delegates. It represents a method containing __a set of criteria__ and __checks whether the passed parameter meets those criteria__. A predicate delegate methods __must take one input parameter and return a boolean__ - ``true`` or ``false``. The Predicate delegate is defined in the ``System namespace``, as shown below: Predicate signature: ``` public delegate bool Predicate<in T>(T obj); ``` Same as other delegate types, Predicate can also be used with __any method, anonymous method, or lambda expression__. ``` static bool IsUpperCase(string str) { return str.Equals(str.ToUpper()); } static void Main(string[] args) { Predicate<string> isUpper = IsUpperCase; bool result = isUpper("hello world!!"); Console.WriteLine(result); } ``` An __anonymous method__ can also be assigned to a Predicate delegate type as shown below. ### Example: Predicate delegate with anonymous method ``` static void Main(string[] args) { Predicate<string> isUpper = delegate(string s) { return s.Equals(s.ToUpper());}; bool result = isUpper("hello world!!"); } ``` A lambda expression can also be assigned to a Predicate delegate type as shown below. ### Example: Predicate delegate with lambda expression ``` static void Main(string[] args) { Predicate<string> isUpper = s => s.Equals(s.ToUpper()); bool result = isUpper("hello world!!"); } ``` --- # [C# - Events](https://www.tutorialsteacher.com/csharp/csharp-event) An event is __a notification sent by an object to signal the occurrence of an action__. Events in .NET follow the __observer design pattern__. __The class who raises events is called Publisher__, and __the class who receives the notification is called Subscriber__. There can be __multiple subscribers__ of a single event. Typically, a publisher raises an event when some action occurred. The subscribers, who are interested in getting a notification when an action occurred, should register with an event and handle it. 與 observer pattern (Publisher / Subscriber) 有關 event 是一個 notification 為 Subscriber 定義 event handler method signature In C#, an event is an encapsulated delegate. It is dependent on the delegate. The delegate __defines the signature for the event handler method of the subscriber class__. ## Declare an Event An event can be declared in two steps: 1. Declare a delegate. 2. Declare a variable of the delegate with event keyword. The following example shows how to declare an event in publisher class. ``` public delegate void Notify(); // delegate public class ProcessBusinessLogic { public event Notify ProcessCompleted; // event } ``` In the above example, we __declared a delegate ``Notify``__ and then __declared an event ProcessCompleted of delegate type Notify using ``event`` keyword in the ``ProcessBusinessLogic`` class. Thus, the ``ProcessBusinessLogic`` class is called the ``publisher``. The Notify delegate specifies the signature for the ProcessCompleted event handler. It __specifies that the event handler method in subscriber class must have a void return type and no parameters__. Now, let's see how to raise the ProcessCompleted event. Consider the following implementation. The following figure illustrates the event in C#. ``` public delegate void Notify(); // delegate public class ProcessBusinessLogic { public event Notify ProcessCompleted; // event public void StartProcess() { Console.WriteLine("Process Started!"); // some code here.. OnProcessCompleted(); } protected virtual void OnProcessCompleted() { //protected virtual method //if ProcessCompleted is not null then call delegate ProcessCompleted?.Invoke(); } } ``` Above, the ``StartProcess()`` method calls the method ``onProcessCompleted()`` at the end, which raises an event. Typically, __to raise an event, ``protected`` and ``virtual`` method should be defined with the name ``On<EventName>``__. ``Protected`` and ``virtual`` enable derived classes __to override__ the logic for raising the event. However, A __derived class should always call the ``On<EventName>`` method of the base class to ensure that __registered delegates receive the event__. The ``OnProcessCompleted()`` method invokes the delegate using ``ProcessCompleted?.Invoke()``;. This will call all the event handler methods registered with the ``ProcessCompleted`` event. The __subscriber class must register to ``ProcessCompleted`` event__ and handle it with the method whose signature matches ``Notify`` delegate, as shown below. ## Consume an Event ``` class Program { public static void Main() { ProcessBusinessLogic bl = new ProcessBusinessLogic(); bl.ProcessCompleted += bl_ProcessCompleted; // register with an event bl.StartProcess(); } // event handler public static void bl_ProcessCompleted() { Console.WriteLine("Process Completed!"); } } ``` Above, the ``Program`` class is a subscriber of the ProcessCompleted event. It __registers with the event using ``+=`` operator__. Remember, this is the same way we add methods in the invocation list of multicast delegate. The ``bl_ProcessCompleted()`` method handles the event because it matches the signature of the ``Notify`` delegate. ``+=`` / ``-=`` 符號 與 delegate multicast 相似, ## Built-in ``EventHandler`` Delegate .NET Framework includes built-in delegate types ``EventHandler`` and ``EventHandler<TEventArgs>`` for the most common events. Typically, any event should include two parameters: __the source of the event and event data__. Use the ``EventHandler`` delegate for __all events that do not include event data__. Use ``EventHandler<TEventArgs>`` delegate for events that include data to be sent to handlers. event source 與 dats The example shown above can use ``EventHandler`` delegate without declaring a custom Notify delegate, as shown below. Example: EventHandler ``` class Program { public static void Main() { ProcessBusinessLogic bl = new ProcessBusinessLogic(); bl.ProcessCompleted += bl_ProcessCompleted; // register with an event bl.StartProcess(); } // event handler public static void bl_ProcessCompleted(object sender, EventArgs e) { Console.WriteLine("Process Completed!"); } } public class ProcessBusinessLogic { // declaring an event using built-in EventHandler public event EventHandler ProcessCompleted; public void StartProcess() { Console.WriteLine("Process Started!"); // some code here.. OnProcessCompleted(EventArgs.Empty); //No event data } protected virtual void OnProcessCompleted(EventArgs e) { ProcessCompleted?.Invoke(this, e); } } ``` In the above example, the event handler ``bl_ProcessCompleted()`` method includes two parameters that match with EventHandler delegate. Also, passing this as a ``sender`` and ``EventArgs.Empty``, when __we raise an event using Invoke() in the OnProcessCompleted() method__. Because we __don't need any data for our event__, it just notifies subscribers about the completion of the process, and so we passed ``EventArgs.Empty``. ## Passing an Event Data Most events send some data to the subscribers. The ``EventArgs`` class is the __base class for all the event data classes__. .NET includes many built-in event data classes such as ``SerialDataReceivedEventArgs``. __It follows a naming pattern of ending all event data classes with ``EventArgs``__. You can __create your custom class for event data by deriving ``EventArgs`` class__. Use ``EventHandler<TEventArgs>`` to pass data to the handler, as shown below. ``` class Program { public static void Main() { ProcessBusinessLogic bl = new ProcessBusinessLogic(); bl.ProcessCompleted += bl_ProcessCompleted; // register with an event bl.StartProcess(); } // event handler public static void bl_ProcessCompleted(object sender, bool IsSuccessful) { Console.WriteLine("Process " + (IsSuccessful? "Completed Successfully": "failed")); } } public class ProcessBusinessLogic { // declaring an event using built-in EventHandler public event EventHandler<bool> ProcessCompleted; public void StartProcess() { try { Console.WriteLine("Process Started!"); // some code here.. OnProcessCompleted(true); } catch(Exception ex) { OnProcessCompleted(false); } } protected virtual void OnProcessCompleted(bool IsSuccessful) { ProcessCompleted?.Invoke(this, IsSuccessful); } } ``` In the above example, we are passing a single boolean value to the handlers that indicate whether the process completed successfully or not. If you want to pass more than one value as event data, then create a class deriving from the ``EventArgs`` base class, as shown below. ## Custom EventArgs Class: ``` class ProcessEventArgs : EventArgs { public bool IsSuccessful { get; set; } public DateTime CompletionTime { get; set; } } ``` ## Passing Custom EventArgs The following example shows how to pass custom ``ProcessEventArgs`` class to the handlers. ``` class Program { public static void Main() { ProcessBusinessLogic bl = new ProcessBusinessLogic(); bl.ProcessCompleted += bl_ProcessCompleted; // register with an event bl.StartProcess(); } // event handler public static void bl_ProcessCompleted(object sender, ProcessEventArgs e) { Console.WriteLine("Process " + (e.IsSuccessful? "Completed Successfully": "failed")); Console.WriteLine("Completion Time: " + e.CompletionTime.ToLongDateString()); } } public class ProcessBusinessLogic { // declaring an event using built-in EventHandler public event EventHandler<ProcessEventArgs> ProcessCompleted; public void StartProcess() { var data = new ProcessEventArgs(); try { Console.WriteLine("Process Started!"); // some code here.. data.IsSuccessful = true; data.CompletionTime = DateTime.Now; OnProcessCompleted(data); } catch(Exception ex) { data.IsSuccessful = false; data.CompletionTime = DateTime.Now; OnProcessCompleted(data); } } protected virtual void OnProcessCompleted(ProcessEventArgs e) { ProcessCompleted?.Invoke(this, e); } } ``` ## Points to Remember: 1. An event is a wrapper around a delegate. It depends on the delegate. 2. Use "event" keyword with delegate type variable to declare an event. 3. Use built-in delegate ``EventHandler`` or ``EventHandler<TEventArgs>`` for common events. 4. The publisher class raises an event, and the subscriber class registers for an event and provides the event-handler method. Name the method which raises an event prefixed with "On" with the event name. The signature of the handler method must match the delegate signature. Register with an event using the ``+=`` operator. Unsubscribe it using the ``-=`` operator. Cannot use the = operator. Pass event data using ``EventHandler<TEventArgs>``. Derive EventArgs base class to create custom event data class. Events can be declared static, virtual, sealed, and abstract. An Interface can include the event as a member. Event handlers are invoked synchronously if there are multiple subscribers. ## [Difference between delegates and events in C#](https://www.tutorialsteacher.com/articles/difference-between-delegate-and-event-csharp) --- * [EventHandler Delegate](https://docs.microsoft.com/en-us/dotnet/api/system.eventhandler?view=netcore-3.1) ``` public delegate void EventHandler(object? sender, EventArgs e); ``` * [``EventHandler<TEventArgs>`` Delegate](https://docs.microsoft.com/en-us/dotnet/api/system.eventhandler-1?view=netcore-3.1) ``` public delegate void EventHandler<TEventArgs>(object? sender, TEventArgs e); ``` * [EventArgs Class](https://docs.microsoft.com/en-us/dotnet/api/system.eventargs?view=netcore-3.1) Represents the base class for classes that contain event data, and provides a value to use for events that do not include event data. ``public class EventArgs`` --- # [在 Entity Framework 使用 Expression 黑魔法做動態條件查詢](https://dotblogs.com.tw/supershowwei/2016/07/25/140345) 看到 ``*.csthml`` 中 有這樣的 expression: ``` @Html.TextBoxFor(m => m.Q_Code, new { title = "!客戶代碼" }) ``` 對應的 Extension method: ``` public static MvcHtmlString TextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes); ``` 其中, ``Expression<Func<TModel, TProperty>> expression`` 是 ``m => m.Q_Code`` m 是 ``ViewModel`` or ``AppQryModel`` (一個自訂的 class) ### [``Expression<TDelegate>`` Class](https://learn.microsoft.com/en-us/dotnet/api/system.linq.expressions.expression-1?view=net-7.0) Represents a strongly typed lambda expression as a data structure in the form of an expression tree. This class cannot be inherited. ``` public sealed class Expression<TDelegate> : System.Linq.Expressions.LambdaExpression ``` ``TDelegate`` 可以是 ``Func<TModel, TProperty>``, e.g., ``` Func<int, bool> funcDelegate = i => i < 5; ``` Delegate 有點像 Kotlin 的 block #### Example ``` // Lambda expression as executable code. Func<int, bool> deleg = i => i < 5; // Invoke the delegate and display the output. Console.WriteLine("deleg(4) = {0}", deleg(4)); // Lambda expression as data in the form of an expression tree. System.Linq.Expressions.Expression<Func<int, bool>> expr = i => i < 5; // Compile the expression tree into executable code. Func<int, bool> deleg2 = expr.Compile(); // Invoke the method and print the output. Console.WriteLine("deleg2(4) = {0}", deleg2(4)); //This code produces the following output: //deleg(4) = True //deleg2(4) = True ``` ### [``Expression<TDelegate>.Compile`` Method](https://learn.microsoft.com/en-us/dotnet/api/system.linq.expressions.expression-1.compile?view=net-7.0) __Compiles the lambda expression__ described by the expression tree __into executable code and produces a delegate__ that represents the lambda expression. 把 Lambda expression 轉換成一個 delegate, 代表可以執行的 code!! ``` public TDelegate Compile (); ``` ``` // Lambda expression as data in the form of an expression tree. System.Linq.Expressions.Expression<Func<int, bool>> expr = i => i < 5; // Compile the expression tree into executable code. Func<int, bool> deleg = expr.Compile(); // Invoke the method and print the output. Console.WriteLine("deleg(4) = {0}", deleg(4)); // This code produces the following output: //deleg(4) = True ```