calendarprovider.Net中的委托与事件(DelegateEvent)
.Net中的委托与事件 DelegateEvent
委托
委托的简单运⽤
⼀个委托类型定义了该类型的实例能调⽤的⼀类⽅法,这些⽅法含有同样的返回类型和同样的参数(形参和个数相同)。委托和接⼝⼀样,可以定义在类的外部。如下定义的⼀个委托类型 - Calculator:
delegate int Calculator (int x);
此委托适⽤任何有着 int 返回类型和⼀个 int 类型参数的⽅法、如:
static int Double (int x)
{
return x *2;
}
创建⼀个委托实例、将该次⽅法赋值给委托实例:
Calculator c =new Calculator(Double);
//简写
Calculator cc = Double;
这个⽅法可以通过委托调⽤
pkiint result =c(2);
完整案例:
class Program
{
delegate int Calculator(int x);
static void Main(string[] args)
{
Calculator c =new Calculator(Double);
Calculator cc = Double;
int result =c(2);
Console.WriteLine(result);
}
static int Double(int x)
{
then
return x *2;
}
}
⽤委托实现插件式编程
我们可以利⽤ “委托是⼀个能把⽅法作为参数传递的对象” 这⼀特点,来实现⼀种插件编程
例如,我们⼜⼀个Utility类,这个类实现⼀个通⽤⽅法(Calculate),⽤来执⾏任何⼜⼀个整型参数和整形返回值的⽅法。如下:
hosting
delegate int Calculator(int num;
public class programizuna
{
static int Double(int num)
{
return num *2;
}
static void Main(string[] args)
{
int[] values ={1,2,3,4};
UtiLity.Calculate(values, Double);
foreach(int i in values)
{
Console.Write(i +" ");
Console.ReadKey();
}
}
旁蒂克}
public class UtiLity
{
public static void Calculate(int[] values, Calculator c)
{
for(int i =0; i < values.Length; i++)
{
values[i]=(values[i]);
}
}
}
这个例⼦中的 Utility 是固定不变的,程序实现了整数的 Double 功能。我们可以把这个 Double ⽅法看作是⼀个插件,如果将来还要实现诸多如平⽅,求⽴⽅的算计,我们只需向程序中不断添加插件就可以了。
如果 Double ⽅法是临时的,只调⽤⼀次,若在整个程序中不会⼜第⼆次调⽤,那么我们可以在Main⽅法中更简洁更灵活的使⽤这种插件式编程,⽆需先定义⽅法,使⽤Lamda表达式即可,如:
Utility.Calculate(values,x => x *2);
多播委托
所有的委托实例都⼜多播的功能。所谓多播,就像是⼀群程序员在瞬聘⽹填好了求职意向后,某天有个公司发布了⼀个和这些程序员求职意向刚好相匹配的⼯作,然后这些求职者都被通知了 - “有⼀份好⼯作招⼈啦,你们可以直接申请去上班了!”。
也就是说,⼀个委托实例不仅可以指向⼀个⽅法,还可以指向多个⽅法。如:
Action act =new Action(DoNothing);//“+=” ⽤来添加,同理“-=”⽤来移除。
act += DoNothing;//act -= DoNothing
act.Invoke();
public static void DoNothing()
口译笔译
{
Console.WriteLine("This is DoNothing");
}
调⽤时,按照⽅法被添加的顺序依次执⾏。注意,对于委托,+= 和 -= 对null是不会报错的,如:
Action dd=null;
dd += DoNothing;// 相当于Action d = DoNothing;
为了更好的理解多播在实际开发中的应⽤,我⽤模拟瞬聘⽹的职位匹配⼩⼯具来做⽰例。在职位匹配过程中会有⼀段处理时间,所以在执⾏匹配的时候要能看到执⾏的进度,⽽且还要把执⾏的进度和执⾏情况写到⽇志⽂件中。在处理完⼀个步骤时,将分别执⾏两个⽅法来显⽰和记录执⾏进度。
我们先定义⼀个委托(ProgressReporter),然后定义⼀个匹配⽅法(Match)来执⾏该委托中的所有⽅法。如下:
public delegate void ProgressReporter(int percentComplete);
public class UtiLity {
public static void Match(ProgressReporter p)
{
if(p !=null)
{
for(int i =0; i <=10; i++)
{
p(i *10);
System.Threading.Thread.Sleep(100);
}
}
}
然后我们需要两个监视进度的⽅法,⼀个把进度写到Console,另⼀个把进度写到⽂件。如下:
ProgressReporter p = WriteProgressToConsole;
p += WriteProgressToFile;
UtiLity.Match(p);
Console.WriteLine("Done.");
Console.ReadKey();
}
static void WriteProgressToConsole(int percentComplete){
Console.WriteLine(percentComplete+"%");
}
static void WriteProgressToFile(int percentComplete){
System.IO.File.AppendAllText("", percentComplete +"%");
}
}
affectionate
运⾏结果:
静态⽅法和实例⽅法对于委托的区别
长颈鹿美语
当⼀个类的实例的⽅法被赋给⼀个委托对象时,在上下⽂中不仅要维护这个⽅法,还要维护这个⽅法所在的实例。System.Delegate 类的Target属性指向的就是这个实例。举个例⼦:
X x =new X();
ProgressReporter p = x.InstanceProgress;
p(1);
Console.WriteLine(p.Target == x);// True
Console.WriteLine(p.Method);// Void InstanceProgress(Int32) }
static void WriteProgressToConsole(int percentComplete){
Console.WriteLine(percentComplete+"%");
}
static void WriteProgressToFile(int percentComplete){
System.IO.File.AppendAllText("", percentComplete +"%");
}
}
class X {
public void InstanceProgress(int percentComplete){
wool
// do something }
}
运⾏结果:
但对于静态⽅法,System.Delegate 类的Target属性是Null,所以将静态⽅法赋值给委托时性能更优。泛型委托
如果你知道泛型,那么就很容易理解泛型委托,说⽩了就是含有泛型参数的委托,例如:
public delegate T Calculator<T>(T arg);
我们可以把前⾯的例⼦改成泛型的例⼦,如下: