委托与事件、匿名方法与Lambda表达式
委托:
委托就是把方法或函数以变量的形式来使用。
委托的使用步骤:
定义方法Func() -> 定义委托类型 -> 声明委托类型的变量 -> 注册方法 -> 调用
1、定义方法
pubic static void Func()
{
Consoe.Writeine("我是一个静态的无参无返回值的方法");
}
2、委托类型(注意)
-> 语法:
pubic deegate 方法签名(参数规则);
-> 拿到方法,删除返回类型前的所有东西与方法参数圆括号后的所有东西
void Func()
-> 在剩下的代码前加上[pubic] deegate
pubic deegate void Func()
-> 在最后加上分号
pubic deegate void Func();
-> 一般在方法名后加上Deegate
pubic deegate void FuncDeegate();
3、使用,定义委托类型的变量
-> 该委托的类型名为
pubic deegate 返回类型 委托类型名(参数);
-> 定义(一般委托变量用Pasca命名规则)
FuncDeegate MyFunc;
4、直接将方法名赋值给委托变量
MyFunc = Func;
// 一旦完成赋值,就表示MyFunc与Func是同一个方法
// 就好像"计算机"与"电脑"的关系一样,是一个方法的两个不同名字
5、调用
方法原本怎么调用,委托变量就怎么调用
原来:Func();
现在:MyFunc();
-> 补充说明
-> 多个类中如何调用
在cass MyCass中写一个方法,然后在Main方法中用委托调用
-> 在定义中系统定义的委托多半以Hander结尾
-> 委托变量赋值
MyFunc = Func;
MyFunc = new FuncDeegate(Func);
// 委托的本质是一个"类"
-> 委托的调用
委托变量();
委托变量.Invoke();
8、 补充——多态
-> 实现的最基本的要求
-> 继承
-> 子类父类有完"全相同的方法"
返回类型 方法名(参数)
-> 父类要virtua或abstract,子类要override
9、 既然委托是类型,我们使用的实际是该类型的变量
既然是变量就可以当做方法的参数进行传递和返回
-> 写一个方法,传入一个整数,在方法中使用整数
pubic static void Func(int num)
{
num *= 2;
Consoe.Writeine(num);
}
传入:就在方法后的圆括号中写上对应类型的局部变量
使用:就是在方法中按照指定规则使用就可以了
-> 写一个方法,传入一个委托变量,并使用
pubic void Func(FuncDeegate aa)
{
aa();
}
10、自定义排序
-> 排序字符串
-> 按照字符串的长度排序
-> 按照字符串的字典排序
-> 先按照一个规则写一个排序算法(冒泡)
strs
for(int i = 0; i < strs.ength - 1; i++)
{
for(int j = 0; j < strs.ength - i - 1; j++)
{
if(strs[j].ength > strs[j+1].ength)
{
string temp = strs[j];
strs[j] = strs[j+1];
strs[j+1] = temp;
}
}
}
-> 思考第二种排序规则是什么,与第一种代码实现的区别是什么
string.Compare(str1, str2)
str1 > str2 1
= 0
< -1
if(string.Compare(strs[j], strs[j+1]) > 0)
{
// 交换
}
多播委托(委托链)
-> 就好像锁链一样,将多个委托一个一个链在一起,调用第一个委托方法,其后的委托方法依次执行
-> 语法:
实现使用:
委托变量 += 方法名; // 追加方法,好比在锁链结尾追加锁链
委托变 量 -= 方法名; // 移除至指定的方法(不用考虑方法在哪里)
-> 使用:
-> 简单的委托链
-> 带有返回值的委托连
调用委托连,返回的是最后一个方法的返回值
如果需要得到委托连中其他方法的返回值,只有一个个调用接收
-> 如果一个方法出现异常,其后所有方法不在执行
事件(event)
-> event 是事件定义的关键字
-> 目标:
-> 什么是事件
-> 事件与委托的区别
-> 如何使用事件(案例)
-> 第一次接触事件
WinForm
-> 事件就是一个委托变量
-> 等待模块
// 伪代码
whie(Consoe.ReadKey().KeyCode != ConsoeInfo.Q)
{
}
-> 事件与委托的区别
委托是类型,而刚刚用的是委托的变量(事件是一个特殊的委托变量)
委托具有灵活性,不安全
-> 使用委托,注册方法可以使用=和+=
使用+=叫追加方法,使用=的时候就是注册方法(一旦=以后,委托链中的方法会清空)
-> 委托在使用的时候为了可以给其添加方法使用了属性或pubic修饰符
谁都可以调用它
-> 事件,就是委托变量的阉割版
-> 不允许使用=赋值,只能使用+=和-=添加和移除方法
-> 不允许外部调用,只能由内部事件触发方法调用
-> 语法:
定义委托变量的时候使用
pubic 委托类型 委托变量;
改为
pubic event 委托类型 事件变量;
-> 说明:
-> 添加事件
10、窗体传值
11、委托的本质与事件的本质(不作要求,以介绍为主)
-> 委托的层次级别
Object
Deegate
MuticastDeegate
用户定义的委托类型
-> 委托的内存处理过程
-> 事件
-> 事件是一个私有的委托变量和两个方法(remove、add)
事件的这两个方法可以看做为属性
1.委托定义了一种新类,该类代表一组具有特定参数及返回类型的方法。声名了委托类型后,必须创建委托对象(实例化)并使之与特定方法关联。对于静态方法,委托对象直接封装要调用的方法。对于实例方法,必须先创建一个类的实例,然后封装该实例上的一个方法。
2.委托大体上相当于C中的函数指针。但与函数指针不同的是,委托是面象对象的和类型安全的。
3.一个委托可以对应多个委托对象,只要方法的签名与委托的最初定义相匹配。委托对象的调用与原方法调用相同。
4.委托不知道或不关心自己实例对象所封装的方法的细节(什么名字或实现什么功能),只要方法的参数类型和返回类型与该委托的参数类型和返回类型相匹配。
-> 调用方法自定义排序
MySort(strs, 方法);
// 传统的处理方法,就是先单独写一个判断大小的方法,在调用这个排序
// 调用MySort方法的使用把比较大小的规则直接写在参数里面
MySort(strs, {s1.Length > s2.Length});
-> 匿名方法,没有名字的方法
-> 就是在代码的执行中定义方法体,运行的时候直接执行(把方法规则写在执行代码中)
-> 语法:
委托类型 委托变量 = delegate(参数) { 方法体 };
int num = 1 + 2;
4、 Lambda表达式(匿名方法的一个衍生)
-> 语法:
(参数) => 执行体;
// => 读作goes to
-> 说明
-> Lambda表达式是一个表达式(注意)
-> ()中的参数,如果没有冲突,可以省略类型
-> Lambda执行体,如果只有一句话,可以省略花括号
-> 返回值的return可以省略
-> Lambda表达式执行体中的变量可以引用到外面(*奇异*)
-> Lambda表达式来源于函数式变成Lisp语言
Erlang一个函数式编程语言
函数式编程语言在并操作中应用非常广泛
Lambda表达式树(晦涩的)
() => 表达式1
=> 表达式2
=> 表达式3
=> 表达式4
=> 表达式5