c#学习笔记之委托

委托

最近本身在调试C#项目,发现常常能够看到委托和lambda表达式,各类花里胡哨的写法把我给整的云里雾里的,因而本身特地花了一点功夫来整理关于delegate的相关知识,方便本身往后查阅。数组

何为委托

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

委托的使用

声明委托

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

咱们能够把委托当作是一件事情,就是给方法名字和返回类型指定一个别名函数

从上面的例子能够总结出声明委托的模板以下:spa

  • 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>调用一个带参数的方法,以此类推;code

// 声明一个返回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);
}

多播委托

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

可是,一个委托也能够包含多个方法,这种委托叫作多播委托,所以,这种委托必须返回void,否则返回的数据是不对的ip

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);
        }
相关文章
相关标签/搜索