Explaining Delegates in C# - Part 1 (Callback and Multicast delegates)
I hear a lot of confusion around Delegates in C#, and today I am going to give it shot of explaining the stuff with easy to understand examples. First things first... I will consciously try NOT to use any technical jargon to explain this concept.
So here we go, without giving any technical explanation, let's start with a console application...
// Declaration
public delegate void VerySimpleDelegate(); class TestDelegate
{
public static void Foo()
{
Console.WriteLine("Foo was called by a delegate!");
} public static void Bar()
{
Console.WriteLine("Bar was called by a delegate!");
} public static void Main()
{
// Instantiation
VerySimpleDelegate vsd = new VerySimpleDelegate(Foo); //#1 // Invocation
vsd(); //Another Instantiation
vsd = Bar;
vsd();
}
}
What do you notice when you run the application? Yes, you are right... you are not calling the functions Foo and Bar directly! Instead, you are creating a delegate (#1). Also notice, you just assigned vsd = Bar, which was another function name. Calling vsd again in the next line called the function called Bar as you can see in the output below!!!
Thus, to use delegate you need to use the following approach... (check the comments in code snipped above to find the following)
Declaration
Instantiation
Invocation
May be you are thinking, why all this headache? What is the need to do all this?
Reason 1> You have to call different functions based on some dynamic requirement but you don't want your function calls to change. In our previous code snipped vsd() doesn't change, although the actual function that it is referring to has changed altogether.
Let's take a look at another sample... Example2
public class Example2
{
// Declaration - Take 1 parameter, return nothing
public delegate void LogHandler(string message); // Instantiation - Create a function which takes delegate as one parameter
// Verify if it is null before you use it
public void Process(LogHandler logHandler)
{
if (logHandler != null)
{
logHandler("Process() begin");
} if (logHandler != null)
{
logHandler("Process() end");
}
}
} public class Example2DelegateConsumer
{
// Create a method with the same signature as the delegate
static void Logger(string s)
{
Console.WriteLine(s);
} public static void Main(string[] args)
{
Example2 ex2 = new Example2(); // Invocation in the client
Example2.LogHandler myLogger = new Example2.LogHandler(Logger);
ex2.Process(myLogger);
}
}
Reason 2> As you can see above, you can use delegates to call static functions. In our case, the function Logger with a parameter was being called by Process function in the Example2 class. This approach is called Callback.
public class Example3
{
// Declaration - Take 1 parameter, return nothing
public delegate void LogHandler(string message); // Instantiation - Create a function which takes delegate as one parameter
// Verify if it is null before you use it
public void Process(LogHandler logHandler)
{
if (logHandler != null)
{
logHandler("Process() begin");
} if (logHandler != null)
{
logHandler("Process() end");
}
}
} public class FileLogger
{
FileStream fs;
StreamWriter sw; // Constructor
public FileLogger(string filename)
{
fs = new FileStream(filename, FileMode.Create);
sw = new StreamWriter(fs);
} // Create a method with the same signature as the delegate
public void Logger(string s)
{
sw.WriteLine(s);
} public void Close()
{
sw.Close();
fs.Close();
}
} public class Example3DelegateConsumer
{
static void Main(string[] args)
{
FileLogger fl = new FileLogger("C:\\Labfiles\\process.log");
Example3 ex3 = new Example3(); // Invocation in the client
// Notice that now instead of Logger function, we are passing fl.Logger function.
Example3.LogHandler myLogger = new Example3.LogHandler(fl.Logger);
ex3.Process(myLogger);
fl.Close();
}
}
Reason 3> Without changing the Example3 delegate, we were able to change the location where a log needs to be written. In the previous example, you would have noticed that we had a Logger function in the same class. Now, we know we can point to any function with the same signature as a delegate from a different class as well. In our example we called the function from the class FileLogger. The key here is that the Logger function is not in the Example3DelegateConsumer class!!!
What if you want to display the results, and write them at the same time??
namespace Delegates4
{
public class Example4
{
// Declaration - Take 1 parameter, return nothing
public delegate void LogHandler(string message); // Instantiation - Create a function which takes delegate as one parameter
// Verify if it is null before you use it
public void Process(LogHandler logHandler)
{
if (logHandler != null)
{
logHandler("Process() begin");
} if (logHandler != null)
{
logHandler("Process() end");
}
}
} public class FileLogger
{
FileStream fs;
StreamWriter sw; // Constructor
public FileLogger(string filename)
{
fs = new FileStream(filename, FileMode.Create);
sw = new StreamWriter(fs);
} // Create a method with the same signature as the delegate
public void Logger(string s)
{
sw.WriteLine(s);
} public void Close()
{
sw.Close();
fs.Close();
}
} public class Example4DelegateConsumer
{
// Create a method with the same signature as the delegate
static void Logger(string s)
{
Console.WriteLine(s);
} static void Main(string[] args)
{
FileLogger fl = new FileLogger("C:\\Labfiles\\process.log");
Example4 ex4 = new Example4(); // Invocation in the client
// Notice that now instead of Logger function, we are passing fl.Logger function
// along with another Logger which is defined in the same class
Example4.LogHandler myLogger = null;
myLogger += new Example4.LogHandler(Logger);
myLogger += new Example4.LogHandler(fl.Logger);
ex4.Process(myLogger);
fl.Close();
}
}
}
Reason 4> As you can see above, we have registered two methods for the same delegate. This is what is typically mentioned as Multicast delegate. By default in C#, delegates are multicast.
I hope this clarifies the basic concepts of delegates, and why you would use them in the first place. In the next post, I will tell you about how to use delegates for events.
转: http://www.dotnetscraps.com/dotnetscraps/post/explaining-delegates-in-c.aspx
Explaining Delegates in C# - Part 1 (Callback and Multicast delegates)的更多相关文章
- Explaining Delegates in C# - Part 7 (Asynchronous Callback - Way 4)
This is the final part of the series that started with... Callback and Multicast delegatesOne more E ...
- Explaining Delegates in C# - Part 6 (Asynchronous Callback - Way 3)
By now, I have shown the following usages of delegates... Callback and Multicast delegatesEventsOne ...
- C# delegate multicast single delegate
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serializatio ...
- Explaining Delegates in C# - Part 4 (Asynchronous Callback - Way 1)
So far, I have discussed about Callback, Multicast delegates, Events using delegates, and yet anothe ...
- Part 36 to 39 Talking about Delegates in c#
Part 36 Delegates in c# Part 37 Delegates usage in c# class Progim { public static void Main() { Lis ...
- c# 关键字delegate、event(委托与事件)[MSDN原文摘录][1]
A delegate is a type that safely encapsulates a method, similar to a function pointer in C and C++. ...
- c++中实现委托
成员函数指针与高性能的C++委托(上篇) 撰文:Don Clugston 引子 标准C++中没有真正的面向对象的函数指针.这一点对C++来说是不幸的,因为面向对象的指针(也叫做"闭包(clo ...
- 为 ngui TweenPosition 添加 pingpongone
//---------------------------------------------- // NGUI: Next-Gen UI kit // Copyright © 2011-2015 T ...
- koa2源码解读及实现一个简单的koa2框架
阅读目录 一:封装node http server. 创建koa类构造函数. 二:构造request.response.及 context 对象. 三:中间件机制的实现. 四:错误捕获和错误处理. k ...
随机推荐
- ClassNotFoundException和NoClassDefFoundError的解决办法
程序在其他手机都没有问题,但在刷到版本稍微较低的平板或手机上时就会直接闪退,并报出以下异常: java.lang.RuntimeException: Unable to instantiate act ...
- R语言如何将字符串转变为命令执行
这里用到 eval() 和 parse() 函数.首先使用 parse() 函数将字符串转化为表达式(expression),而后使用 eval() 函数对表达式求解.x <- 1:10a &l ...
- SAP HR模块的基础数据表和增强配置
信息类型是SAP HR模块数据单元,用于对人员数据的记录和维护,是HR的基础.信息类型按照其创建方式的不同可以分为:人事信息类型.组织信息类型.信息类型数据的维护主要在事物码PA30.PA40.po1 ...
- 用不上索引的SQL语句
下面介绍六种建立索引后不起作用的sql语句. 1.使用不等于操作符(<>, !=) SELECT * FROM dept WHERE staff_num <> 1000; × ...
- unity---------------------关于BuildAssetBundles的使用(打包)
using UnityEditor;using UnityEngine; public class BuildAssetBundle{ /// <summary> /// 点击后,所有设置 ...
- Python——hashlib
该模块实现了诸多安全哈希和消息摘要算法的通用接口,包括 FIPS 安全哈希算法: SHA1, SHA224, SHA256, SHA384 和 SHA512 算法(在 FIPS 180-2 中定义), ...
- #HTTP协议学习# (四)疑问篇
1.为什么使用fiddler看不到旺旺客户端登录时发送的请求? 客户端是使用什么样的方式进行认证? 一般都是用HTTPS来加密Http request. 这样代理服务器就看不到里面的数据了.(why ...
- Linux下yum命令详解
yum是什么yum = Yellow dog Updater, Modified主要功能是更方便的添加/删除/更新RPM包.它能自动解决包的倚赖性问题.它能便于管理大量系统的更新问题yum特点 可以同 ...
- MySQL提示“错误2:系统找不到指定文件”
一.问题原因 个人猜测可能是因为安装的是绿色版MySQL,然后在系统变量path中加入了解压后的路径.后续操作上没有跳转到解压后的路径,而是直接在cmd的默认路径下新建MySQL的服务,所以导致此问题 ...
- u3d资源打包只能打包场景材质,不能打包脚本
GameObject附带脚本打包进来以后,只有一个脚本名字,估计只是关联了脚本,内容却不在,所以后面打包资源的话,一定要把脚本,shader之类的,放到工程目录下