C#-委托事件匿名函数lambda表达式闭包

一、委托

1.概念:

委托是函数(方法)的容器 ,可以理解为表示函数(方法)的变量类型。用来存储、传递函数(方法)
​ 委托的本质是一个类,用来定义函数(方法)的类型(返回值和参数的类型),不同的函数(方法)必须对应和各自"格式"一致的委托

2.语法:

关键字 : delegate
​ 语法:访问修饰符 delegate 返回值 委托名(参数列表);
​ 可以申明在 namespace 和 class 语句块中,更多的写在 namespace 中

​ 简单记忆委托语法,就是函数申明语法前面加一个 delegate 关键字

3.自定义委托

// 访问修饰默认不写 为public 在别的命名空间中也能使用            
// private 其它命名空间就不能用了                      
// 一般使用public                               
                                           
// 申明了一个可以用来存储无参无返回值函数的容器                   
// 这里只是定义了规则 并没有使用                          
internal delegate void MyFun();            
                                           
// 委托规则的申明 是不能重名(同一语句块中)                    
// 表示用来装载或传递 返回值为int 有一个int参数的函数的 委托 容器规则   
public delegate int MyFun2(int a);         
                                           
// 委托是支持 泛型的 可以让返回值和参数 可变 更方便我们的使用          
internal delegate T MyFun3<T, K>(T v, K k);

4.使用委托

// 使用定义好的委托                                                                          
                                                                                               
// 委托变量是函数的容器                                                                                   
                                                                                               
// 委托常用在:                                                                                       
// 1.作为类的成员                                                                                     
// 2.作为函数的参数                                                                                    
internal class Test                                                                            
{                                                                                              
    public Action action;                                                                      
    public MyFun  fun;                                                                         
    public MyFun2 fun2;                                                                        
                                                                                               
    public void TestFun(MyFun fun, MyFun2 fun2) {                                              
        // 先处理一些别的逻辑 当这些逻辑处理完了 再执行传入的函数                                                         
        int i = 1;                                                                             
        i *= 2;                                                                                
        i += 2;                                                                                
                                                                                               
        // fun();                                                                               
        // fun2(i);                                                                             
        // this.fun = fun;                                                                      
        // this.fun2 = fun2;                                                                    
    }                                                                                          
                                                                                               
                                                                                               
    // 增                                                                                  
                                                                                               
    public void AddFun(MyFun fun, MyFun2 fun2) {                                               
        this.fun  += fun;                                                                      
        this.fun2 += fun2;                                                                     
    }                                                                                          
                                                                                               
    // 删                                                                                  
                                                                                               
    public void RemoveFun(MyFun fun, MyFun2 fun2) {                                            
        //this.fun = this.fun - fun;                                                           
        this.fun  -= fun;                                                                      
        this.fun2 -= fun2;                                                                     
    }                                                                                            
}                                                                                              
                                                                                               
// 委托变量可以存储多个函数(多播委托)                                                                     
                                                                                               
internal class Program                                                                         
{                                                                                              
    private static void Main(string[] args) {                                                  
        Console.WriteLine("委托");                                                               
        // 专门用来装载 函数的 容器                                                                        
        MyFun f = Fun;                                                                         
        Console.WriteLine("1");                                                                
        Console.WriteLine("2");                                                                
        Console.WriteLine("3");                                                                
        Console.WriteLine("4");                                                                
        Console.WriteLine("5");                                                                
        f.Invoke();                                                                            
                                                                                               
        MyFun f2 = Fun;                                                                        
        Console.WriteLine("1");                                                                
        Console.WriteLine("2");                                                                
        Console.WriteLine("3");                                                                
        Console.WriteLine("4");                                                                
        Console.WriteLine("5");                                                                
        f2();                                                                                  
                                                                                               
        MyFun2 f3 = Fun2;                                                                      
        Console.WriteLine(f3(1));                                                              
                                                                                               
        MyFun2 f4 = Fun2;                                                                      
        Console.WriteLine(f4.Invoke(3));                                                       
                                                                                               
        Test t = new Test();                                                                   
                                                                                               
        t.TestFun(Fun, Fun2);                                                                  
        Console.WriteLine("***************");                                                  
        // 如何用委托存储多个函数                                                                          
        MyFun ff = null;                                                                       
        // ff = ff + Fun;                                                                       
        ff += Fun;                                                                             
        ff += Fun3;                                                                            
        ff();                                                                                  
        // 从容器中移除指定的函数                                                                          
        ff -= Fun;                                                                             
        // 多减 不会报错 无非就是不处理而已                                                                    
        ff -= Fun;                                                                             
        ff();                                                                                  
        // 清空容器                                                                                 
        ff = null;                                                                             
        if (ff != null) ff();                                                                  
                                                                                               
        // 系统定义好的委托                                                                  
                                                                                               
        // 使用系统自带委托 需要引用using System;                                                           
        // 无参无返回值                                                                               
        Action action = Fun;                                                                   
        action += Fun3;                                                                        
        action();                                                                              
                                                                                               
        // 可以指定返回值类型的 泛型委托                                                                      
        Func<string> funcString = Fun4;                                                        
        Func<int>    funcInt    = Fun5;                                                        
                                                                                               
        // 可以传n个参数的  系统提供了 1到16个参数的委托 直接用就行了                                                    
        Action<int, string> action2 = Fun6;                                                    
                                                                                               
        // 可以穿n个参数的 并且有返回值的 系统也提供了 16个委托                                                        
        Func<int, int> func2 = Fun2;                                                                                
    }  
                                                                                      
    private static void Fun() {                                                   
        Console.WriteLine("张三做什么");                                               
    }                                                                             
                                                                                  
    private static void Fun3() {                                                  
        Console.WriteLine("李四做什么");                                               
    }                                                                             
                                                                                  
    private static string Fun4() {                                                
        return "";                                                                
    }                                                                             
                                                                                  
    private static int Fun5() {                                                   
        return 1;                                                                 
    }                                                                             
                                                                                  
    private static void Fun6(int i, string s) { }                                 
                                                                                  
    private static int Fun2(int value) {                                          
        return value;                                                             
    }                                                                             
}

委托就是装载、传递函数的容器而已
​ 可以用委托变量来存储函数或者传递函数
​ 系统其实已经提供了很多委托给我们用
​ Action:没有返回值,参数提供了 0~16个委托给我们用
​ Func:有返回值,参数提供了 0~16个委托给我们用

二、事件

1.概念

  1. 事件是基于委托的存在
  2. 事件是委托的安全包裹
  3. 让委托的使用更具有安全性
  4. 事件是一种特殊的变量类型

2.事件的使用

// 申明语法:                                                             
// 访问修饰符 event 委托类型 事件名;                                             
// 事件的使用:                                                            
// 1.事件是作为 成员变量存在于类中                                                 
// 2.委托怎么用 事件就怎么用                                                    
// 事件相对于委托的区别:                                                       
// 1.不能在类外部 赋值                                                       
// 2.不能在类外部 调用                                                       
// 注意:                                                               
// 它只能作为成员存在于类和接口以及结构体中                                              
internal class Test                                                 
{                                                                   
    // 委托成员变量 用于存储 函数的                                               
    public Action myFun;                                            
                                                                    
    public Test() {                                                 
        // 事件的使用和委托 一模一样 只是有些 细微的区别                                  
        myFun =  TestFun;                                           
        myFun += TestFun;                                           
        myFun -= TestFun;                                           
        myFun();                                                    
        myFun.Invoke();                                             
        myFun = null;                                               
                                                                    
        myEvent =  TestFun;                                         
        myEvent += TestFun;                                         
        myEvent -= TestFun;                                         
        myEvent();                                                  
        myEvent.Invoke();                                           
        myEvent = null;                                             
    }                                                               
                                                                    
    // 事件成员变量 用于存储 函数的                                               
    public event Action myEvent;                                    
                                                                    
    public void DoEvent() {                                         
        if (myEvent != null) myEvent();                             
    }                                                               
                                                                    
    public void TestFun() {                                         
        Console.WriteLine("123");                                   
    }                                                               
}                                                                   
                                                                    
// 为什么有事件                                                 
                                                                    
// 1.防止外部随意置空委托                                                      
// 2.防止外部随意调用委托                                                      
// 3.事件相当于对委托进行了一次封装 让其更加安全                                          
                                                                    
#endregion                                                          
                                                                    
internal class Program                                              
{                                                                   
    private static void Main(string[] args) {                       
        Console.WriteLine("事件");                                    
                                                                    
        Test t = new Test();                                        
        // 委托可以在外部赋值                                                 
        t.myFun =  null;                                            
        t.myFun =  TestFun;                                         
        t.myFun =  t.myFun + TestFun;                               
        t.myFun += TestFun;                                         
        // 事件是不能再外部赋值的                                               
        // t.myEvent = null;                                         
        // t.myEvent = TestFun;                                      
        // 虽然不能直接赋值 但是可以 加减 去添加移除记录的函数                               
        t.myEvent += TestFun;                                       
        t.myEvent -= TestFun;                                       
                                                                    
        // 委托是可以在外部调用的                                               
        t.myFun();                                                  
        t.myFun.Invoke();                                           
        // 事件不能再外部调用                                                 
        // t.myEvent();                                              
        // 只能在类的内部去封装 调用                                             
        t.DoEvent();                                                
                                                                    
        Action a = TestFun;                                         
        // 事件 是不能作为临时变量在函数中使用的                                       
        // event Action ae = TestFun;                                
    }                         
                                          
    private static void TestFun() { } 
}                             

三、匿名函数

// 基本语法                                                              
                                                                               
// delegate (参数列表)                                                              
// {                                                                            
//     //函数逻辑                                                                   
// };                                                                           
// 何时使用?                                                                        
// 1.函数中传递委托参数时                                                                 
// 2.委托或事件赋值时                                                                   
                                                                               
// 使用                                                                
                                                                               
// 1.无参无返回                                                                      
// 这样申明匿名函数 只是在申明函数而已 还没有调用                                                     
// 真正调用它的时候 是这个委托容器啥时候调用 就什么时候调用这个匿名函数                                          
Action a = delegate { Console.WriteLine("匿名函数逻辑"); };                          
                                                                               
a();                                                                           
// 2.有参                                                                         
Action<int, string> b = delegate(int a, string b) {                            
    Console.WriteLine(a);                                                      
    Console.WriteLine(b);                                                      
};                                                                             
                                                                               
b(100, "123");                                                                 
// 3.有返回值                                                                       
Func<string> c = delegate { return "123123"; };                                
                                                                               
Console.WriteLine(c());                                                        
                                                                               
// 4.一般情况会作为函数参数传递 或者 作为函数返回值                                                   
Test   t  = new Test();                                                        
Action ac = delegate { Console.WriteLine("随参数传入的匿名函数逻辑"); };                   
t.Dosomthing(50, ac);                                                          
//   参数传递                                                                       
t.Dosomthing(100, delegate { Console.WriteLine("随参数传入的匿名函数逻辑"); });            
                                                                               
//   返回值                                                                        
Action ac2 = t.GetFun();                                                       
ac2();                                                                         
// 一步到位 直接调用返回的 委托函数                                                            
t.GetFun()();                                                                  
                                                                               
// 匿名函数的缺点                                                           
                                                                               
// 添加到委托或事件容器中后 不记录 无法单独移除                                                      
                                                                               
Action ac3 = delegate { Console.WriteLine("匿名函数一"); };                         
                                                                               
ac3 += delegate { Console.WriteLine("匿名函数二"); };                               
                                                                               
ac3();                                                                         
// 因为匿名函数没有名字 所以没有办法指定移除某一个匿名函数                                                 
// 此匿名函数 非彼匿名函数 不能通过看逻辑是否一样 就证明是一个                                              
// ac3 -= delegate ()                                                           
// {                                                                            
//     Console.WriteLine("匿名函数一");                                              
// };                                                                           
ac3 = null;                                                                    
// ac3();                            

四、lambda表达式

// 什么是lambad表达式                                                          
                                                                                   
// 可以将lambad表达式 理解为匿名函数的简写                                                          
// 它除了写法不同外                                                                         
// 使用上和匿名函数一模一样                                                                     
// 都是和委托或者事件 配合使用的                                                                  
                                                                                   
// lambad表达式语法                                                           
                                                                                   
// 匿名函数                                                                             
// delegate (参数列表)                                                                  
// {                                                                                
                                                                                    
// };                                                                               
                                                                                   
// lambad表达式                                                                        
// (参数列表) =>                                                                        
// {                                                                                
//     //函数体                                                                        
// };                                                                               
                                                                                   
// 使用                                                                    
                                                                                   
// 1.无参无返回                                                                          
Action a = () => { Console.WriteLine("无参无返回值的lambad表达式"); };                       
a();                                                                               
                                                                                   
// 2.有参                                                                             
Action<int> a2 = value => { Console.WriteLine("有参数Lambad表达式{0}", value); };        
a2(100);                                                                           
                                                                                   
// 3.甚至参数类型都可以省略 参数类型和委托或事件容器一致                                                     
Action<int> a3 = value => { Console.WriteLine("省略参数类型的写法{0}", value); };           
a3(200);                                                                           
                                                                                   
// 4.有返回值                                                                           
Func<string, int> a4 = value => {                                                  
    Console.WriteLine("有返回值有参数的那么大表达式{0}", value);                                 
    return 1;                                                                      
};                                                                                 
Console.WriteLine(a4("123123"));                                                   
                                                                                   
// 其它传参使用等和匿名函数一样                                                                   
// 缺点也是和匿名函数一样的

五、闭包

        闭包是一种语言特性,它允许在函数内部定义的函数访问外部函数的局部变量。即使外层函数执行已终止。
        在C#中我们可以使用Lambda来实现闭包闭包本质是一个对象(编译后),但使用上它和方法一致。使用闭包我们就可以实现拥有私有状态的函数!

定义

        我们把在Lambda表达式(或匿名方法)中所引用的外部变量称为捕获变量。而捕获变量的表达式就称为闭包

捕获变量

        捕获的变量会在真正调用委托时“赋值”,而不是在捕获时“赋值”,即总是使用捕获变量的最新的值

// 闭包                                                      
                                                                   
// 内层的函数可以引用包含在它外层的函数的变量                                              
// 即使外层函数的执行已经终止                                                      
// 注意:                                                                
// 该变量提供的值并非变量创建时的值,而是在父函数范围内的最终值。                                    
                                                                     
internal class Test                                                  
{                                                                    
    public Test() {                                                  
        int value = 10;                                                                           
        action = () => { Console.WriteLine(value); }; 
        // 方法体加+字段 这里就形成了闭包                                                   
        // 因为 当构造函数执行完毕时  其中申明的临时变量value的声明周期被改变了               
                                                                     
        for (int i = 0; i < 10; i++) {                               
            // 此index 非彼index                                         
            int index = i;                                           
            action += () => { Console.WriteLine(index); };           
        }                                                            
    }                                                                
                                                                     
    public event Action action;                                      
                                                                     
    public void DoSomthing() {                                       
        action();                                                    
    }  
}
static void Main(string[] args)
        {
            GetAction()(30);
        }

        static Action<int> GetAction()
        {
            int arg = 10;

            Action<int> action = x =>
            {
                Console.WriteLine(x + arg);
            };
            action(10);

            arg = 20;
            action(20);

            arg = 30;

            return action;
        }
output:
20
40
60

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值