• 委托 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});