委托 02

来源:互联网 发布:unity3d 过山车轨道 编辑:程序博客网 时间:2024/04/30 13:48
1. 多播委托:
a. 含义:一个委托可以添加多个方法。
        b. 实质:多播委托其实就是委托的父类(MulticastDelegate)
c. 使用:// 委托追加一个方法
myDelegate1.MyDG += SetMessage1; // 编译后实际上是  (MyDelegate)Delegate.Combine(myDelegate1.MyDG, new MyDelegate(this.SetMessage));
// 移除委托中的一个方法
myDelegate1.MyDG -= SetMessage; // 编译后实际上是  (MyDelegate)Delegate.Remove(myDelegate1.MyDG, new MyDelegate(this.SetMessage));
d. 注意: 1. 多播委托的方法签名返回值只能是void,否则只能调用最后一个方法
 2. 多播委托在遍历方法时,如果其中一个的方法爆出异常,会终止后面的方法执行。
    自己循环: MyDG.GetInvocationList(); // 取出委托中的函数数组
2. 匿名方法:
a. 含义: 没有方法名和返回值,用delegate声明的函数,它存在函数的内部。
b. 实质:在编译后其实还是一个方法。用匿名方法只是为了减少代码,不用去为了一个委托而当独定义个方法。
c. 使用:delegate int Plus(int num1, int num2);
static void Main(string[] args)
{
Plus plus = delegate(int num1, int num2)
{
return num1 + num2;
};
Console.WriteLine(plus(2, 5)); // 输出的是7
Console.ReadKey();
}
d. 注意:1. 不能使用break,continue,goto语句等跳转语句跳转到方法外部,也不能从方法外部跳转到方法内部。
2. 在方法内部不能使用方法外部用ref,out定义的变量,但是可以使用其他的变量。(闭包。PS: foreach等 也有闭包)
3. Lambda表达式
a. 含义: 就是把委托简化的一种语法
b. 使用: 1. 一个参数
delegate void Plus(int num);
static void Main(string[] args)
{
Plus plus1 = num =>  Console.WriteLine(num + 10);
plus1(12);
Console.ReadKey();
}
  2. 多个参数
  delegate void Plus(int num1, int num2);
  static void Main(string[] args)
  {
Plus plus1 = (num1, num2) => { Console.WriteLine(num1 + num2); };
plus1(12, 20);
Console.ReadKey();
  }
  3. 方法体有多条语句
Plus plus1 = (num1, num2) => {
int sum = 0;
sum = num1 + num2;
Console.WriteLine(sum);
};
4. 事件
a. 为什么使用事件: 1.在使用委托的时候,我们可以在对象存在的地方随意添加,删除事件。为了不让这种情况存在。我们可以自己封装委托
/// <summary>
/// 委托
/// </summary>
/// <param name="strMsg"></param>
public delegate void MyDG(string strMsg);

class DGTestClass
{
/// <summary>
/// 为了安全,应该把委托变量设置为私有的
/// </summary>
private MyDG myDG;

/// <summary>
/// 添加一个方法
/// </summary>
/// <param name="dg"></param>
public void Add(MyDG dg)
{
myDG += dg;
}

/// <summary>
/// 移除一个方法
/// </summary>
/// <param name="dg"></param>
public void Remove(MyDG dg)
{
myDG -= dg;
}
}
2. 微软为了方便,给我们提供了一个语法糖,他会自动生成上面的那些东西。 也就是事件
public event MyDG myDG1; // 只需要这样写就可以了,编译器在编译的时候,会把myDG1变量私有化,并生成一个同名的事件语法,里面包含了2个方法(添加、删除)

编译后的IL代码:
.field private class 事件.MyDG myDG1;
.event 事件.MyDG myDG1
{
.addon intance void 事件.DGTestClass::add_myDG1(clss 事件.MyDG );
.removeon intance void 事件.DGTestClass::remove_myDG1(clss 事件.MyDG );
}
  PS: IL代码中的事件是我的命名空间的名称
b. 事件发布程序(发行者),事件侦听器(订阅者),订阅
委托变量所在的类就是  发行者
方法所在的类或者说是谁要调用这个事件就是  订阅者
把两者关联起来(+=)就是  订阅
0 0