Working with Delegates

Working with Delegates
 
We all are well aware about functions. In conventional way, we create object and we call object.method(). We know that they perform some given task and returns results based on the parameters we passed to them. Now please look at the following cases.
 
Why do we need delegates?
 
Case 1:
 
You have a business class where you have some functions F1, F2, F3 (with similar signatures). You have completed the project and you are using function F2 in so many places, around 100 locations. Now there is a change request that you are supposed to use F3 and not F2. Now the only way you have is, to go back to those 100 places and find/replace your F2 with F3.
 
Wouldn't it be awesome if you have somebody to represent the function F2, so that you can just tell him not to execute F2 and instead he has to make use of function F3? In such case, the change has to be made only in ONE location - to the representative alone. Yes, delegates are your functional representatives. They are nothing but functional pointers. They are nothing but command objects that will work based on your commands. Delegate represents strongly typed functions.
 
Case 2:
 
What if you want to execute those three functions one by one? What if you want your representative to take care of more than one method? Multicast delegates will give you a hand. We will discuss this later.
 
Case 3:
 
Assume your function F1 takes long time to execute. You are forced to wait until it gets completed, before you are allowed to proceed with function F2. You can cross this hurdle by making use of asynchronous call with the help of delegates.
 
Case 4:
 
You are in a situation where you wanted to pass a method as a parameter to another method. There you have delegates that can be treated as a data type as others do.
 
Case 5:
 
Assume you are in a situation where you want the parameters of your methods to be treated in different logics. The logic that needs to be used has to be passed through your front layer. To make it simple, you have to pass two numbers to a function and the logic of treatment, i.e. whether it has to be added or subtracted or multiplied; has to be decided by the front layer. Here delegates are most welcome.
 
Method and Target
 
Every delegate has its own method and target properties. The prime idea of this is nothing but to invoke the method in target object.
 
Simple Approach
 
Assume there are two functions for a class say, DelegateManager (dm).
 
  • public void SayHello(string input)
  • public void Display (string display)
Note they both take string parameter and both of them are void method. In other words, they both have similar signature. You can represent this by a delegate.
 
public delegate string MyDelegate(string str);
 
Instances of this delegate can represent any of these two methods.
 
// using same delegate to execute both the functions
MyDelegate d1 = new MyDelegate(dm.SayHello);
MyDelegate d2 = new MyDelegate(dm.Display);
 
Note down there is no parenthesis while declaring the functions. We are passing functional pointer to the delegate. You can just invoke the delegate by,
 
d1("abc");
d2("cde");
 
Every instance of the delegate will represent the given method. MyDelegate cannot represent any other class, which does not match the type.
 
As we discussed in case 4, you can also treat methods (i.e. delegates) as data types. You can pass them anywhere you wish to.
 
Inversion of Controls – IOC
 
Let us look at a class our business control where I need to add 100 and 25. I am going to make use of the Add method of a Calculator class.
 
Business Control:
 
public delegate int CalculatorHandler(int x, int y);
public class business
{
    public int CallMe(CalculatorHandler ch)
    {
        // Note i am making use of Calculator class
        // without its reference
        int result = ch(100,25);
        return result;
    }
}
 
Front layer:
 
private void button2_Click(object sender, EventArgs e)
{
    Calculator c = new Calculator();
    BusinessControl.business bc = new BusinessControl.business();
    BusinessControl.CalculatorHandler ch = new BusinessControl.CalculatorHandler(c.Add);
    // IOC technique
    int Result = bc.CallMe(ch);
    MessageBox.Show(Result.ToString());
}
 
This technique is called IOC (Inversion of Control), i.e. the control is injected at runtime. We are using the 'bc' business control to which the delegate has to be passed.
 
You can toggle between methods of similar signatures by changing the function pointer. If you want to work with Divide method, just replace c.Add with c.Divide, that’s it.
 
Usage in Real time
 
Let us assume your business class needs to call n number of functions f1, f2, f3 & f4 in a specific order.
 
Assume there is a change request, that you want to insert a new function between f2 and f3 and f4 to be replaced with f5. All you have in front is to do mere Replace.
 
Instead if I had followed IOC, the business class is not related to any of the functions, in turn it executes delegates.
 
A mediator will create instance of business rules and then pass it on to business logic. If you run business control with specific business rule, the best way is to use mediator pattern.
 
Multicast delegates

As we have discussed in the earlier session, delegates represents functional pointers. When a delegate represents multiple methods, it is multi cast delegates.
 
Multicast delegates should represent void methods. By adding += I am making this delegate to multicast. The moment I add this += it becomes an array !. This would hold as many numbers of methods as you specify.

// Normal delegate
Calculator c = new Calculator();
BusinessControl bc = new BusinessControl();
CalculatorHandler ch = new CalculatorHandler(c.Add);
MessageBox.Show(bc.CallMe(ch).ToString()); 
//call add method - > this technique is called IOC           
// multi cast delegate
Calculator c = new Calculator();
BusinessControl bc = new BusinessControl();
CalculatorHandler ch = new CalculatorHandler(c.Add);
ch += new CalculatorHandler(c.Add);
ch += new CalculatorHandler(c.Multiply);
MessageBox.Show(bc.CallMe(ch).ToString());

Here is how it works. When you invoke the delegate, 'Add' method will be called first followed by 'Multiply' in a single thread and the compiler will come back to you once it is done with all methods specified in the multicast delegate.
 
Note that you will get a response back only after completing both the tasks ie. Add and Multiply. This is the reason it is suggested that Multicast delegates should represent only void methods.
 
Hope this might have given you an idea of multicast delegates.  Let us look at what is Synchronized and Asynchronized communications and how delegates support these features.
 
Synchronized Communication

In our previous example, when we call Add() method of calculator class, using oCalc.Add(), we are making a synchronized communication. Meaning, we are waiting for Calculator object to complete its Add method.  To test this, add a Thread.Sleep(10000) in the add method. When we call this method, the current thread will be in sleep mode for 10000 milliseconds. In other words, we are forced to wait until the compiler is done with the Add method.

public
int Add(int a, int b)
{
    Thread.Sleep(10000);
    Console.WriteLine((a + b).ToString());
    return (a + b);
}

It is not possible to call any other method untill 10000 ms is completed. This is called synchronous communication.
 
Practical implementation: Think of a complex stored-procedure that takes 10000 ms to execute. We cannot proceed with next step until the procedure is completed and the compiler gets back to the code.

Asynchronous Communication
 
Asynchronous methods will not wait for the completion of current thread, and hence we can proceed with next.
 
This is something like we delegate the work to a third person to do the task on our behalf.

Having said this, how about getting a notification from that person once he completes the tasks?  Sounds good isn't it? We will discuss about this later.
 
To try asynchronous methods, we are adding Thread.Sleep(10000) to both Add() and Multiple() methods of Calculator class. This is nothing but to demonstrate the waiting period. Please refer to the below sections.

Synchronize Call - Normal

Calculator c = new Calculator();
BusinessControl bc = new BusinessControl();
CalculatorHandler ch = new CalculatorHandler(c.Add);
MessageBox.Show(bc.CallMe(ch).ToString());
 
You will notice that, until it is completed we won't be able to do any other task and the entire application would be locked. Try typing something in the textbox during this invocation.
 
Converting to Asynchronize Call

Calculator
c = new Calculator();
CalculatorHandler ch = new CalculatorHandler(c.Add);
ch.BeginInvoke(100, 25, null, null);

ch = new CalculatorHandler(c.Multiply);           
ch.BeginInvoke(25, 4, null, null);
 
Now type something in a textbox.
 
What is Begin Invoke

The moment you call BeginInvoke, you are creating a fork.  Meaning, each delegate will be executed in different threads through BeginInvoke. 
 
The current thread will be splitted into three. One will represent the main thread from which the delegates are called, one will go for the C.ADD method and the other one will be used for the C.MULTIPLY method.
 
What is End Invoke
 
EndInvoke is nothing but just opposite action of BeginInvoke. This will create a Join ie, it will wait for all other threads to complete and combine them all together into one single thread and proceed with the Main thread.
 
Getting results from Asynchronous call - Long running processes

Here I would like to introduce a new member IAsynchResult interface. It takes responsibility to get the work done by the delegate and bring the result back to your location.  IAsynchResult.IsCompleted returns true when the asynchronous job is completed; until that time it is false and you can continue with your work. Hence we can use this to assess whether the long running process is completed.

private
    IAsyncResult ar1 = ch.BeginInvoke(100, 25, null, null);
   
int Counter = 0;
    while (!ar1.IsCompleted)
    {
        // Do other stuffs
        Counter++;
    }
    // Now we know that call is completed as IsCompleted has returned true
    textBox1.Text = Counter.ToString() + " times i was doing my other work";
    intResult = (int)ch.EndInvoke(ar1);
    MessageBox.Show(intResult.ToString());
}
 
Now what about Out parameters?
 
So how are we supposed to deal with out parameters of our method?  Let us take a look at the Add method which takes a parameter int as Out. Here's how it goes,
 
Int Add(Int,int,out int).   
 
Then use,
BeginInvoke(int,int,null,null) and the EndInvoke will be EndInvoke(out int).
 
Call Back Mechanism - Completion Notification

The idea is to make the calculator come back and say I have finished my work and this is the result. This mechanism is called Callback.
void button4_Click(object sender, EventArgs e)
{
    Int32 intResult;
    Calculator c = new Calculator();
    CalculatorHandler ch = new CalculatorHandler(c.Add);
技术选型 【后端】:Java 【框架】:springboot 【前端】:vue 【JDK版本】:JDK1.8 【服务器】:tomcat7+ 【数据库】:mysql 5.7+ 项目包含前后台完整源码。 项目都经过严格调试,确保可以运行! 具体项目介绍可查看博主文章或私聊获取 助力学习实践,提升编程技能,快来获取这份宝贵的资源吧! 在当今快速发展的信息技术领域,技术选型是决定一个项目成功与否的重要因素之一。基于以下的技术栈,我们为您带来了一份完善且经过实践验证的项目资源,让您在学习和提升编程技能的道路上事半功倍。以下是该项目的技术选型和其组件的详细介绍。 在后端技术方面,我们选择了Java作为编程语言。Java以其稳健性、跨平台性和丰富的库支持,在企业级应用中处于领导地位。项目采用了流行的Spring Boot框架,这个框架以简化Java企业级开发而闻名。Spring Boot提供了简洁的配置方式、内置的嵌入式服务器支持以及强大的生态系统,使开发者能够更高效地构建和部署应用。 前端技术方面,我们使用了Vue.js,这是一个用于构建用户界面的渐进式JavaScript框架。Vue以其易上手、灵活和性能出色而受到开发者的青睐,它的组件化开发思想也有助于提高代码的复用性和可维护性。 项目的编译和运行环境选择了JDK 1.8。尽管Java已经推出了更新的版本,但JDK 1.8依旧是一种成熟且稳定的选择,广泛应用于各类项目中,确保了兼容性和稳定性。 在服务器方面,本项目部署在Tomcat 7+之上。Tomcat是Apache软件基金会下的一个开源Servlet容器,也是应用最为广泛的Java Web服务器之一。其稳定性和可靠的性能表现为Java Web应用提供了坚实的支持。 数据库方面,我们采用了MySQL 5.7+。MySQL是一种高效、可靠且使用广泛的关系型数据库管理系统,5.7版本在性能和功能上都有显著的提升。 值得一提的是,该项目包含了前后台的完整源码,并经过严格调试,确保可以顺利运行。通过项目的学习和实践,您将能更好地掌握从后端到前端的完整开发流程,提升自己的编程技能。欢迎参考博主的详细文章或私信获取更多信息,利用这一宝贵资源来推进您的技术成长之路!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值