C#复习笔记(六)
委托 delegate
表示函数(方法)的变量类型,可用来存储、传递函数(方法)
委托的本质是一个类,用来定义函数(方法)的类型
不同的函数(方法)必须对应和各自“格式”一致的委托
可以声明在namespace和class语句块中,写在namespace较多
语法:访问修饰符 delegate 返回值 委托名(参数列表)
申明一个可以用来存储无参无返回值函数的容器
delegate void MyFun(); //定义规则并没有使用
委托在同一语句块中不能重名
delegate int MyFun2(int a); //用来装载或传递返回值为int,有一个int参数的函数的委托容器规则
delegate T MyFun<T,K>(T t,K k);
访问修饰符不写默认为public,在别的namespace也能用
使用private其他namespace就不能使用
MyFun f = new MyFun(Fun);
f.Invoke();
MyFun f2 = Fun;
f2();
//上述两种写法都可以执行Fun()函数
static void Fun()
{
Console.Write("114514");
}
使用定义好的委托
class Test
{
public MyFun fun;
public MyFun2 fun2;
public void TestFun(MyFun fun , MyFun2 fun2)
{
int i = i +6;
//可以处理别的逻辑,再执行传入的函数
//直接执行
fun();
fun2(i);
//存起来,之后再执行
this.fun = fun;
this.fun2 = fun2;
}
}
//使用
Test t = new Test();
t.TestFun(Fun,Fun2)
多播委托(委托变量存储多个函数)
按添加函数的顺序,先加的先执行
MyFun d = Fun;
d += Fun; //相当于d = d+Fun;
d();
//会执行两次Fun函数
d -= Fun; //d = d - Fun;
d = null; //清空容器
当用有返回值的委托容器存储多个函数时
如果直接调用,虽然多个函数都会执行,但是返回值只能获取到最后一个
解决方法:
使用函数容器中的方法GetInvovationList() //可以返回一个委托数组
foreach(Func<string> del in funTest.GetInvocationList()){}
系统自带的委托 Action
无参无返回的委托
public Action action;
指定返回值类型的泛型委托
Func<>
可以传n个参数委托(系统提供了1到16个)
Action<int , string> action = Fun;
可以传n个参数并有返回值(系统也提供1到16个)
Func<int , string> func = Fun; //int参数,string返回值
事件 event
事件是基于委托的存在,是委托的包裹
让委托的使用更具安全性
语法:访问修饰符 event 委托类型 事件名;
事件是作为成员变量存在于类中,用法和委托相同
事件和委托的区别:
1、不能在类外部赋值
2、不能在类外部调用(可以在内部封装后调用)
事件只能作为成员存在于类和接口以及结构体中
事件不能在外部赋值,但可以通过加减去移除记录的函数
class Test
{
public event Action myEvent;
public Test()
{
myEvent = TestFun;
myEvent += TestFun;
myEvent -= TestFun;
myEvent();
myEvent.Invoke;
myEvent = null;
}
public void TestFun()
{
}
//封装后才能在外部调用
public void DoEvent()
{
if(myEvent != null)
{
myEvent();
}
}
}
为什么有事件
1、防止外部随意置空委托
2、防止外部随意调用委托
3、事件相当于对委托进行了一次封装,让其更安全
匿名函数
没有名字的函数
主要是配合委托和事件进行使用
脱离委托和事件是不会使用匿名函数
函数中传递委托参数时,委托和事件赋值时使用
语法:delegate(参数列表){};
//用Action存起来
Action a = delegate(){}//声明无参无返回匿名函数
a();
//有参
Action<int , string > b = delegate(int a,string b){};
//有返回值
Func<string> c = delegate(){};
参数传递:
一般情况会作为函数参数传递或作为函数返回值
用Action装后再传入
直接在参数声明匿名函数
x.TestFun(delegate(){
Console.Write();
});
当返回值内有个匿名函数时
x.TestFun() (); //可用第二个括号直接调用返回的委托函数
匿名函数缺点
添加到委托或事件容器中后,不记录就无法单独移除
匿名函数没有名字,无法指定移除某个匿名函数
lambda表达式
匿名函数的简写,除了写法不同,使用上和匿名函数都相同
都是配合事件或者委托使用
语法:(参数列表) =>{};
无参无返回:
Action a = () =>{};
a();
有参数:
Action<int> b = (int value) =>{};
b(114514);
参数类型可省略(因为前面的容器已经声明了):
Action<int> c = (value) =>{};
c(1919810);
有返回值:
Func<string , int> d = (value) =>{ return 1 ;};
d(666);
缺点和匿名函数相同
闭包
内层函数可以引用包含在它外层函数的变量(该变量提供的值不是创建时的值,而是在父函数范围内的最终值)
即使外层函数的执行已经终止
List排序
系统自带类的排序
List<int> list = new List<int>();
list.Sort(); //List提供的排序方法
自定义类的排序
继承IComparable<>接口,实现接口中的CompareTo方法
CompareTo的返回值含义:
小于0放在传入对象前面
等于0保持当前位置不变
大于0放在传入对象后面
public int CompareTo(Item other)
{
if(this.money > other money)
{
return 1;
}
else
{
return -1;
}
}
通过委托函数进行排序
类不需要继承接口
通过使用Sort的重载,其中有个重载是使用委托来排序
Item.Sort(delegate(item a, item b) {
return a.id > b.id ? 1 : -1;
});
Item.Sort((a,b) => { return a.id > b.id ? 1 : -1});