委托事件

委托:调用回调方法的一种类型安全的方式。(确保回调方法是类型安全的)

允许顺序调用多个方法并支持调用静态方法和实例方法。

声明委托的目的是为了包装N个相同签名的方法。

委托的作用:

作用一:

1、可以帮助将方法作为参数使用。

  1.1委托里可以包含签名与委托一致的方法。

  1.2委托里包含地方法访问权限和委托本身的访问权限无关。

  1.3凡是将方法直接赋给委托对象的地方,编译时都会帮我们使用生成对应的new委托方法。

2、委托能帮我们封装一个函数指针,供程序员调用。(委托本质上就是一个类,继承于MultcastDelegate->Delegate)

3、匿名方法

  3.1并不是真的没有名字,它在CLR编译时会产生一个临时方法名。

  3.2匿名方法产生后,那个指针会存放在委托变量中供程序调用。

作用二:

1、可以向委托上注册多个方法。

2、也可以从委托上移除已注册的方法。

3、如果委托上注册了多个有返回值的方法,那么调用后委托返回的是最后一个方法的返回值。

 

多播委托中追加新方法的步骤:

例如:dgh1+=dgh2;

1、声明一个object数组。(数组中存储的就是多播委托对象)

2、判断两个要组合的委托类型是否一致。

3、将要追加的委托对象里的object数组取出来。

4、如果追加的不为空,则取出里面的元素个数。

5、将dgh1里的object数组取出:

  5.1如果数组等于null,则将dgh2里的数组个数+1。(准备一个新的数组长度为dgh2里方法个数+1)

  5.2将dgh1直接放在数组第一个元素位置。

  5.3如果dgh2的方法数组为空,则直接将dgh2设置到新数组第二个元素。

在运行+=注册方法时,其实创建了第三个委托,然后将两个委托里所有的方法都用委托对象包装后存入第三个委托中。

 

delegate void MyTranslateDelegate(string str,int s)

private void btn_click()

{

//new一个委托对象,必须传入一个相同方法签名的方法

MyTranslateDelegate dg=new MyTranslateDelegate(TranslateTCN);

//可以不使用new关键字,直接将签名相同的方法赋值给委托对象

MyTranslateDelegate dg=TranslateToCN;

//调用委托,可以直接把委托对象作为方法使用

dg("ss",123);

//调用委托,可以通过委托对象的Invoke方法来调用

dg.Invoke("ss",123);

//将委托对象作为参数传递

Translate(dg,"ss",123);

Translate(TranslateToCN,"ss",123);

}

void Translate(MyTranslateDelegate dg,string str,int a)

{

dg(str,a);

}

void TranslateToCN(string str,int s)

{

Console.WriteLine("");

}

 

委托排序:

public class Person
{
public string name { get; set; }
public int age { get; set; }
}

 

private void btnDelegateSort_Click(object sender, EventArgs e)
{

//定义一个人类集合
List<Person> listPerson = new List<Person>()
{
new Person() { name = "123", age = 10 },
new Person() { name = "456", age = 30},
new Person() { name = "sss", age = 23 },
new Person() { name = "qwe", age = 26}
};
foreach (Person item in listPerson)
{
MessageBox.Show("name:" + item.name + " age:" + item.age);
}

Comparison<Person> s = new Comparison<Person>(Comparison);

listPerson.Sort(Comparison);
MessageBox.Show("排序后:");
foreach (Person item in listPerson)
{
MessageBox.Show("name:" + item.name + " age:" + item.age);
}

}

//排序规则,按age排序

public int Comparison(Person p1, Person p2)
{
if (p1.age > p2.age)
{
return 1;
}
else if (p1.age < p2.age)
{
return -1;
}
else
return 0;
}

 

泛型委托取最大值:

delegate int CompareDelegate<T>(T value1,T value2);

void btnGetMax_Click(object sender,EventArgs e)

{

Person[] perArr={

new Person(){name="范冰冰",age=25},

new Person(){name="王菲",age=26},

new Person(){name="孙燕姿",age=26}

}

Person olestp=(Person)GetMax<Person>(perArr,compareFun<Person>);

MessageBox.Show("name:"+olestp.name+" age:"+olestp.age);

}

int CompareFun<T>(T a,T b)

{

Person p1 =a as Person;

Person p2=b as Person;

return p1.age-p2.age;

}

//取最大值

T GetMax<T>(T[] objs,CompareDelegate<T> compare)

{

T maxObj=objs[0];

foreach(T obj in objs)

{

if(compare(maxObj,obj)<0)

{

maxObj=obj;

}

}

return maxObj;

}

 

另:

Func 可以传入16个参数,返回方法的返回值。

 

事件:

使用委托保存方法指针,有可能出现不小心把前面注册的方法清除的危险。

事件只提供+=、-=操作,杜绝了程序员的误操作。

事件就是为了约束一个委托对象的操作方法,对外只提供+=、-=操作。

event关键字好处:创建了一个对应的私有委托的对象,封装了对私有委托对象的外部操作。

event会自动生成一个private delegate变量和两个函数:add和remove。C#编译器用这两个方法支持+=和-=操作符。

内部实现:

private MyDelegate OnEvent;

public void Add(MyDelegate d)

{

OnEvent+=d;

}

public void Remove(Delegate d)

{

OnEvent-=d;

}

因为OnEvent是private的,所以在类外部不能OnEvent()触发事件,但是在类内部可以。

public的方法只有Add和Remove,所以只能+=、-=,其他的操作都是不可以的。

 

委托和事件没有可比性,因为委托是类型,事件是对象。

事件的内部使用委托实现的。因为对于事件来讲,外部只能“注册自己+=、注销自己-=”,外界不可以注销其他的注册者,外界不可以主动触发事件,因此如果用Delegate就没法进行上面的控制,因此诞生了事件这种语法。

 

posted @ 2017-05-07 11:34  jechsky  阅读(144)  评论(0编辑  收藏  举报