我看委托(三)
1.委托
写程序的时候,根据传递的参数,确定调用的是哪个函数,但我有一点疑问,委托的对象不是指向函数名,委托的参数不是和函数名的参数一样,那么这样为什么还不能确定调用的是哪个方法呢?
委托可以认为具有相同签名和返回值类型的有序方法列表。
当委托被调用时,它调用方法列表中的每一个方法。
第一步:声明委托
delegate 返回值类型 委托类型名(参数名); 没有方法主体
delegate void adelegate(string a);
第二步:既然委托没有方法主体,那么我就要声明一个方法主体,否则将没有任何意义。
这个时候,就可以根据委托来进行方法的声明。
static 返回值类型 方法名(参数名)
{
方法主体
}
static void Say(string a)
{
Console.WriteLine("aaa");
}
第三步:在程序中进行委托的调用
既然是进行委托的调用,那么委托对象首先要指向要调用的方法,如果委托没有指向任何方法名,那么也就谈不上委托对方法列表进行调用了。
★★★委托类型声明委托对象如何对方法进行调用呢?可以有这两种方法。
1)直接声明一个委托对象然后指向要调用的方法名即可。
adelegate adel = Say;
adel("11");
2)实例化一个委托对象,把方法名当做参数传递过去,然后在进行委托的调用。
adelegate adel = new adelegate(Say);
adel("11");
2.委托如何调用多个方法
★★★★★上面说的是委托对方法列表中的一个方法进行调用,那么能不能对多个方法进行调用呢?当然是可以的了,委托的一个特重要的目的就是对多个方法一起进行调用。
adelegate adel = new adelegate(Say)+Hellow; //进行多个方法的调用时,委托指向的第一个方法必须被实例化。
adel("11");
static void Say(string a)
{
Console.WriteLine("aaa");
}
static void Hellow(string b)
{
Console.WriteLine("bbb");
}
delegate void adelegate(string a);
★★★★★通过上面的例子我们可以看出,委托是如何对多个方法进行调用的。
3.下面我们通过一个例子,可以更进一步看出委托是如何扣窟窿的。
List<int> list1 = new List<int>();
list1.Add(10);
list1.Add(-15);
list1.Add(14);
list1.Add(-8);
list1.Add(6);
list1.Add(3);
foreach (int i in list1)
{
if (i > 10)
{
Console.WriteLine("i大于10的{0}",i);
}
}
foreach (int i in list1)
{
if (i%2==0)
{
Console.WriteLine("i为偶数的{0}",i);
}
}
foreach (int i in list1)
{
if (i< 0)
{
Console.WriteLine("i小于0的{0}",i);
}
}
★★★★★通过上面的例子,我们发现没次对i进行判断,都要进行一次循环声明,如果细心点会发现,上面唯一不同的地方是if条件的判断。
4.通过一个WinForm程序引入事件的概念
(1)一个简单的委托在窗体间调用的例子
第一步:在用户控件中自定义一个按钮,声明委托,委托的对象,当用户点击自定义按钮时,如果委托不为null的时候,调用用户传递过来的委托方法。
public delegate void adelegate(); //声明一个委托
public adelegate adel;//声明一个委托对象。
private void button1_Click(object sender, EventArgs e)
{
if (adel != null)
{
adel();
}
}
(2)在窗体中的构造函数中,声明当前用户控件btnuser的委托指向的方法是
btnuser.adel = Say;
(3)然后声明委托调用的方法
void Say()
{
MessageBox.Show("点击了");
}
5.如何进行委托的清除如伪造
对使用的控件进行修改
btnuser.adel = null; //清除用户控件的委托为空null
if(btnuser.adel!=null) //如果用户控件的委托不为空的话
btnuser.adel(); //进行用户控件的冒充
★★★★★既然存在着这样的问题,那么如何进行保护呢,避免可能出现的清除与监听呢?
(1)如果把声明委托的对象改成private的话,那么虽都无法进行访问,这种方法,显然是不好的。
那么如何进行避免呢,可以有以下两种方法,把委托声明为私有的,在方法中进行添加委托的调用。
private adelegate adel;
public void Ade(adelegate d)
{
adel += d;
}
内部使用的还是私有的委托对象。
if (adel != null)
{
adel();
}
★★★★★但外部的话,就需要通过方法传递调用列表了。
btnuser.Ade(Say); 用户控件 委托方法(调用列表中的方法名)
(2)使用事件来避免清除与冒充
★★★★★委托是类型,事件是用委托来实现的其实就是字段或属性。
event 委托类型 事件名{add remove}
事件成员可以用+=、-=调用add、remove方法
public event SanQiangDelegate OnSanQiang
{
//add remove最终也是编译生成两个方法
//当用户sanQiangButton1.OnSanQiang += _SAnQiang1添加监听的时候
//就会调用add方法,value就是添加的委托
add
{
_onSanQiang += value;
}
remove
{
_onSanQiang -= value;
}
}
★★★★★外部使用事件的时候,必须+= 或-=
btnuser.adel += Say;