zoukankan      html  css  js  c++  java
  • c#学习笔记之委托

    委托

    最近自己在调试C#项目,发现经常可以看到委托和lambda表达式,各种花里胡哨的写法把我给整的云里雾里的,于是自己特意花了一点功夫来整理关于delegate的相关知识,方便自己日后查阅。

    何为委托

    委托是.NET中的寻址方法,和C++的函数指针很像;但是委托是类型安全的类,定义了返回类型和参数类型,也就是说委托一种用户自定义的类型,和普通的类一样;

    委托的使用

    声明委托

        delegate void IntMethodInvoker(int x);    //定义委托IntMethodInvoker, 参数是int,返回类型void
    

    我们可以把委托当做是一件事情,就是给方法名字和返回类型指定一个别名

    从上面的例子可以总结出声明委托的模板如下:

    • delegate + 返回类型 + 委托类型名 + 参数列表

    委托的使用

    实例化委托,并且需要对其进行初始化,这样可以类似地当做一个变量使用了,下面给出一个具体的例子来说明如何使用委托。

        using System;
        
        namespace DelegateSamples{
        
            delegate double DoubleOp(double x);    // 声明一个委托类型
            class MathOperations
            {
                public static doube MultiplyByTwo(double value)
                    return value * 2;
        
                public static double Square(double value)
                    return value * value;
            }
            
            class Program
            {
                static void Main()
                {
                    // 声明一个委托数组,就像普通数组一样
                    DoubleOp[] operations = {MathOperations.MultiplyByTwo, MathOperations.Square};
                    
                    for(int i = 0; i < operations.length; i++)
                    {
                        Console.WriteLine("using operations[{0}]:", i);
                        ProcessAndDisplayNumber(operations[i], 3.2);
                        Console.WriteLine();
                    }
                }
            
                static void ProcessAndDisplayNumber(DoubleOp action, double value)
                {
                    double res = action(value);         // 调用action实际封装的方法
                    Console.WrireLine("Value is {0}, result of operation is {1}", value, res);
                }
             }
    

    在调用委托的时候,最后判断委托是否为null,不然可能会引起异常

    Action和Func委托

    Action<T>委托表示引用一个void返回类型的方法,Action<T>有很多种变体,Action<in T>调用带一个参数的方法,没有泛型参数的Action类调用不带参数的方法;
    Func<T>委托类似,表示引用带返回类型的方法,Func<T>也有很多变体,Func<Out TResult>表示调用带返回类型但没有参数的方法,Func<in T, out TRsult>调用一个带参数的方法,以此类推;

    // 声明一个返回double类型,并且带一个double参数的委托
    Func <double, double> operations = {MathOperations.MultiplyByTwo, MathOperations.Square};
    
    // 注意这个方法和上面方法的不一样,利用了Func类
    static void ProcessAndDisplayNumber(Func <double, double> action, double value)
    {
            double res = action(value);         // 调用action实际封装的方法
            Console.WrireLine("Value is {0}, result of operation is {1}", value, res);
    }
    

    多播委托

    在之前的例子中,每个委托都只含有一个方法调用,也就是说调用多少次委托就是调用多少次方法。

    但是,一个委托也可以包含多个方法,这种委托叫做多播委托,因此,这种委托必须返回void,不然返回的数据是不对的

        Action<double> operations = MathOperations.MultiplyByTwo;
        operations += MathOperations.Square;    //这里在给委托添加一个方法
    

    对于多播委托的使用,调用方法链的顺序并没得到正式定义,这要求我们尽量避免依赖特定顺序调用方法的代码;

    从上面的例子可以知道,多播委托是可以识别+,+=,-,-=这些符号的,下面给出具体的示意:

    • +=: 表示委托新增一个方法
    • -=: 表示委托减少一个方法

    匿名方法

    在上面的例子中,委托所调用的方法,都是我们自己预先写好的,但是委托也可以使用匿名方法,也就是将匿名方法用作委托的参数,这在实例化委托的会有一些不一样的,具体如下面例子所示:

        string name = "";
        
        // Func<string, string>委托接受一个string参数,返回一个string,注意匿名方法的实现,delegate开头
        Func<string, string> anonDel = delegate(string param){
            param += name;
            param += "just for test";
            return param;
        };
    

    使用匿名方法需要遵守的规则:

    1. 在匿名方法中不能使用跳转语句(goto、break、continue),匿名方法外部的语句也不能跳转到匿名方法内部;
    2. 在匿名方法中不能访问不完全的代码,也不能访问在匿名方法外部定义的ref、out参数;

    在C#3.0之后,lambda表达式代替了匿名方法,写起来感觉更舒服;

    Lambda表达式

    lambda表达式主要是用来替代匿名方法的,因为显然委托知道他自己需要调用的是什么方法,不需要声明delegate关键字,在参数和方法体之间插入=>,表示“goes to",具体示例如下所示:

        string name = "";
        
        // Func<string, string>委托接受一个string参数,返回一个string,这里使用lambda表达式
        Func<string, string> anonDel = param => {
            param += name;
            param += "just for test";
            return param;
        };
       // 这样的lambda表达式是不是很优雅,就是调试程序的时候会有点烦
    

    为了更好地使用lambda表达式,方便我们自己写代码写的花里花哨的,就对其多做一点介绍:

    参数

    1. 如果只有一个参数,就只需要写出参数名字就行

       Func<string, string> oneParam = s => String.Format("change to Upper {0}", s.ToUpper());
      
    2. 使用多个参数,就把参数用写在()里

      Func<double, double, double> twoParams= (x, y) => x * y;    // 返回x*y
      

    在使用多个参数的时候,我觉得还是在参数前面加上类型比较好,便于理解,例如(double x, double y) => x * y;

    多行代码

    1. 只有一条语句,方法里面不需要{}和return,编译器会自动添加一个隐式的return

       Func<double, double, double> result = x, y => x * y;
      
    2. 含有多条语句,需要加上{}和return

      string lastname = "Alex";
      Func<string ,string> printName = name =>
          {
              name += lastname;
              return String.Format("Being Upper: {0}",name);
          }
  • 相关阅读:
    yocto添加源码并编译进文件系统
    yocto编译加速及单独编译内核与uboot
    mysql 创建索引
    redis初使用
    mysql修改时区
    linux修改时间
    服务器环境配置安装(mysql+redis+nodejs+nginx)
    由于找不到MSVCP20.dll,无法继续执行代码
    sequelize初使用
    css flex
  • 原文地址:https://www.cnblogs.com/zuixime0515/p/12343572.html
Copyright © 2011-2022 走看看