委托和事件
1、代理类型
C++和其他语言一样可以通过函数指针来进行访问,但在C#中取消了指针的概念,因为指针可能给程序的安全的安全性带来隐患为了弥补知道指针对语言灵活性的影响,C#引入一种新的类型,即代理(Delegate)。但是在2.0中我们称它委派。
2、委托概述
委托是一种引用类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。例如:
public delegate string Handler(string str);
注意:1.与委托的签名(由返回类型和参数组成)匹配的任何方法都可以分配给该委托。这样就可以通过编程方式来更改方法调用,还可以向现有类中插入新代码。只要知道委托的签名,便可以分配自己的委托方法。
2.将方法作为参数进行引用的能力使委托成为定义回调方法的理想选择。
3.委托可以定义在命名空间里面,也可以定义在类里边。
3、委托的特点(from msdn)
委托具有以下特点:
1.委托类似于 C++ 函数指针,但它是类型安全的。
2.委托允许将方法作为参数进行传递。(重要应用之一)
3.委托可用于定义回调方法。
4.委托可以链接在一起(多路广播);例如,可以对一个事件调用多个方法。
假如我们在开发的过程中,一个类中要用的另外一个类中的方法。那我们应该怎么做呢?
有人说直接在那个类中定义方法就行呀,考虑到代码重用性,此举不妥。用接口,可以;匿名方法也行。但是考虑简单的我们用委托(委托别人去办)看看。(但这不是委托的最理想的应用)
4、如何实现委托
看这样一个用例:父母没有时间来照顾孩子,我们来委托保姆来照看孩子。我们抽象一下:
public class Parents
{
public delegate string LookAfterChild(string childname);//定义委托。分配给为委托的方法必须和委托有相同的签名,也即参数和返回值必须一致。
public double Work(string time,double price)
{
return time * price;
}
}
public class Amah
{
public double LookAfterChild(string time,double price)
{
return time * price;
}
}
调用看看:
Amah amah = new Amah();
//委托定义在Parents类中
Parents.LookAfterDelegate lookafter = new Parents.LookAfterDelegate(amah.LookAfterChild); daleagate.Text= lookafter(12, 12).ToString();
结果:144
如果代理在命名空间下:
Amah amah = new Amah();
DelegateClass.LookAfterDelegate lookafter = new LookAfterDelegate(amah.LookAfterChild);
daleagate.Text= lookafter(12, 12).ToString();
结果:144
5、多路广播委托
上面的委托只包含了一个方法,其实可以委托也可以包含多个方法。这些方法必须要有相同的返回值和参数列表且参数类型一致,这种委托就是多路广播委托。多路广播委托派生于System.MulticastDelegate,它的Combine方法允许把多个方法调用链接在一起,我们可以通过+=来向委托添加调用方法,也可以用-=删除其中的调用方法。也可以通过+或者-来实现.用+ -和+=的区别是+-创建了新委托对象。
为了得到更好的体现,我们选择控制台:
delegate void Del(string s);//定义委托
class TestClass
{
static void Hello(string s)
{
System.Console.WriteLine(" Hello, {0}", s);
}
static void Goodbye(string s)
{
System.Console.WriteLine(" Goodbye, {0}", s);
}
static void
{
a = Hello;
b = Goodbye;
c = a + b;//新委托对象
d = c - a;
System.Console.WriteLine("调用委托a:");
a("A");
System.Console.WriteLine("调用委托a:");
b("B");
System.Console.WriteLine("调用委托c:");
c("C");
System.Console.WriteLine("调用委托d:");
d("D");
}
}
结果是:
调用委托 a:
Hello, A
调用委托 b:
Goodbye, B
调用委托 c:
Hello, C
Goodbye, C
调用委托 d:
Goodbye, D
注意,多路广播委托声明时必须返回void,否则返回值不知道应该送回什么地方。对此,我做了一个测试:如果不将委托的声明返回void,则返回值返回的是最后一个链入委托链的方法的返回值,编译不会出错。
看下面的示例:
public delegate string
public class TestClass
{
public string Hello(string s)
{
return "Hello" + s;
}
public string Goodbye(string s)
{
return "Goodbye" + s;
}
}
protected void Page_Load(object sender, EventArgs e)
{
TestClass test=new TestClass();
c = a + b;//最后链入委托列表的方法为test.Goodbye();
d = c - a;
int i=c.GetInvocationList().GetLength(0);//跟踪委托列表中的方法数
this.daleagate.Text = i.ToString();
Response.Write(a("A") + "</br>");
Response.Write(b("B") + "</br>");
Response.Write(c("C") + "</br>");
Response.Write(d("D") + "</br>");
}
结果: HelloA
GoodbyeB
GoodbyeC
GoodbyeD
6、为什么要用委托
使用委托使程序员可以将方法引用封装在委托对象内。然后可以将该委托对象传递给可调用所引用方法的代码,而不必在编译时知道将调用哪个方法。与C或C++中的函数指针不同,委托是面向对象,而且是类型安全的。