zoukankan      html  css  js  c++  java
  • .Net自带的委托类型—Func,Action 和 Predicate

    委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递。

    与其他的类不同,委托类具有一个签名,并且它只能对与其签名匹配的方法进行引用。

    一、自定义委托类型

    1.语法结构:访问修饰符 delegate 返回类型 委托类型名称(参数列表);

    例如:

    // 声明一个委托类型,两个参数均为int类型,返回值为int类型
    public delegate int Calc(int a, int b);

    自定义的委托可以不带参数,也可以没有返回值。

    接下来我们看一个例子怎么使用委托

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 委托
    {
        class Program
        {
            // 声明一个委托类型,两个参数均为int类型,返回值为int类型
            public delegate int Calc(int a, int b);
    
            // 定义和委托签名一致的方法(参数类型和个数,返回值类型均一致)
            static int Add(int a, int b)
            {
                return a + b;
            }
    
            static int Sub(int a, int b)
            {
                return a - b;
            }
    
            static int Multi(int a, int b)
            {
                return a * b;
            }
    
            static int Divis(int a, int b)
            {
                if (b == 0)
                {
                    throw new Exception("除数不能为0!");
                }
    
                return a / b;
            }
    
            static void Main(string[] args)
            {
                Console.WriteLine("请输入第一个数:");
                int a = int.Parse(Console.ReadLine());
    
                Console.WriteLine("请输入第二个数:");
                int b = int.Parse(Console.ReadLine());
    
                // 定义一个Calc委托类型的变量,把和该委托签名一致的Add方法的引用赋值给变量
                Calc method = Add;
                Console.WriteLine("加法运算:{0}+{1}={2}", a, b, method(a, b));
    
                method = Sub;
                Console.WriteLine("减法法运算:{0}-{1}={2}", a, b, method(a, b));
    
                method = Multi;
                Console.WriteLine("乘法运算:{0}×{1}={2}", a, b, method(a, b));
    
                method = Divis;
                Console.WriteLine("除法运算:{0}÷{1}={2}", a, b, method(a, b));
    
                Console.ReadKey();
            }
        }
    }


    2.匿名方法

    给上述委托变量赋值时,必须先定义好一个和委托签名一致的方法。使用匿名方法,你就无需先定义好那些方法,直接通过delegate语法给委托变量赋值。

    匿名方法的结构:delegate(参数列表){函数体};

    例如:

    Calc method = delegate(int x, int y)
                {
                    return x + y;
                };


    使用匿名方法重新实现上述例子:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 匿名方法
    {
        class Program
        {
            // 声明一个委托类型,两个参数均为int类型,返回值为int类型
            delegate int Calc(int a, int b);
    
            static void Main(string[] args)
            {
                Console.WriteLine("请输入第一个数:");
                int a = int.Parse(Console.ReadLine());
    
                Console.WriteLine("请输入第二个数:");
                int b = int.Parse(Console.ReadLine());
    
                // 定义一个Calc委托类型的变量
                Calc method = delegate(int x, int y)
                {
                    return x + y;
                };
                Console.WriteLine("加法运算:{0}+{1}={2}", a, b, method(a, b));
    
                method = delegate(int x, int y)
                {
                    return x - y;
                };
                Console.WriteLine("减法法运算:{0}-{1}={2}", a, b, method(a, b));
    
                method = delegate(int x, int y)
                {
                    return x * y;
                };
                Console.WriteLine("乘法运算:{0}×{1}={2}", a, b, method(a, b));
    
                method = delegate(int x, int y)
                {
                    return x / y;
                };
                Console.WriteLine("除法运算:{0}÷{1}={2}", a, b, method(a, b));
    
                Console.ReadKey();
            }
        }
    }

    反编译生成的exe文件,你会发现编译器自动帮你生成了4个与自定义委托类型签名一致的方法,并且Main方法中的匿名方法变成了Lamdba表达式的形式,如图:

    3.Lamdba表达式

    Lamdba表达式其实就是一种语法糖,让你更能简洁的编写代码。

    其语法结构:(参数列表)=>{函数体};

    用Lamdba表达式实现上述例子:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Lamdba表达式
    {
        class Program
        {
            // 声明一个委托类型,两个参数均为int类型,返回值为int类型
            delegate int Calc(int a, int b);
    
            static void Main(string[] args)
            {
                Console.WriteLine("请输入第一个数:");
                int a = int.Parse(Console.ReadLine());
    
                Console.WriteLine("请输入第二个数:");
                int b = int.Parse(Console.ReadLine());
    
                // 定义一个Calc委托类型的变量
                Calc method = (x, y) => { return x + y; };
                Console.WriteLine("加法运算:{0}+{1}={2}", a, b, method(a, b));
    
                method = (x, y) => x - y; // 也可以这样写
                Console.WriteLine("减法法运算:{0}-{1}={2}", a, b, method(a, b));
    
                method = (x, y) => { return x * y; };
                Console.WriteLine("乘法运算:{0}×{1}={2}", a, b, method(a, b));
    
                method = (x, y) => { return x / y; };
                Console.WriteLine("除法运算:{0}÷{1}={2}", a, b, method(a, b));
    
                Console.ReadKey();
            }
        }
    }

    你也可以反编译生成的exe文件,你会发现结果与匿名方法反编译的效果一样。

    二、.Net自带的委托类型

    1.Func委托类型

    Func是有返回值的泛型委托,可以没有参数,但最多只有16个参数,并且必须要有返回值,不能为void类型。如图:

    Func<int, int, int> // 第一,二个参数为int类型,返回值为int类型
    Func<string, string, bool> // 第一,二个参数string类型,返回值为bool类型
    Func<int, string, decimal> // 第一个参数为int类型,第二个参数为string类型,返回值为decimal类型

    同自定义的委托类型一样,你可以为Func委托变量赋值为方法引用,匿名方法或者Lamdba表达式:

    (1)方法引用

    (2)匿名方法

    (3)Lamdba表达式

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Func委托类型
    {
        class Program
        {
            static int Add(int a, int b)
            {
                return a + b;
            }
    
            static void Main(string[] args)
            {
                //Func<int, int, int> method = Add;
                //Func<int, int, int> method = delegate(int a, int b) { return a + b; };
    
                Func<int, int, int> method = (x, y) => { return x + y; };
                
                Console.WriteLine("加法运算:{0}+{1}={2}", 3, 4, method(3, 4));
                Console.ReadKey();
            }
        }
    }

    2.Action委托类型
    Action是没有返回值的泛型委托,可以没有参数,但最多只有16个参数,返回值为void类型。如图:

    直接看例子:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Action委托类型
    {
        class Program
        {
            static void Main(string[] args)
            {
                Action<string, string> method = (s1, s2) => { Console.WriteLine(s1 + s2); };
                
                method("1+1=", "2");
                Console.ReadKey();
            }
        }
    }

    3.Predicate委托类型
    Predicate是只有一个参数,且返回值为bool类型的泛型委托。

    // 摘要:
    //     表示定义一组条件并确定指定对象是否符合这些条件的方法。
    //
    // 参数:
    //   obj:
    //     要按照由此委托表示的方法中定义的条件进行比较的对象。
    //
    // 类型参数:
    //   T:
    //     要比较的对象的类型。
    //
    // 返回结果:
    //     如果 obj 符合由此委托表示的方法中定义的条件,则为 true;否则为 false。
    public delegate bool Predicate<in T>(T obj);

    直接看例子:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Predicate委托类型
    {
        class Program
        {
            static void Main(string[] args)
            {
                Predicate<int> method = (x) => { return x > 3; };
    
                Console.WriteLine(method(4));// 输出:True
                Console.ReadKey();
            }
        }
    }


    三、综合应用

    这些自带的委托类型在泛型集合中使用的比较多,如:

    接下来再看一个综合例子:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 运用
    {
        class Program
        {
            static void Main(string[] args)
            {
                List<Student> list = new List<Student> 
                {
                    new Student{Name="张三",Age=24},
                    new Student{Name="李四",Age=32},
                    new Student{Name="王五",Age=36},
                    new Student{Name="马六",Age=45},
                    new Student{Name="李七",Age=28}
                };
    
                // Func委托类型
                List<Student> list2 = list.Where(item => item.Age < 30).ToList();
                foreach (Student stu in list2)
                {
                    Console.WriteLine("姓名:{0},年龄:{1}。", stu.Name, stu.Age);
                }
                Console.WriteLine("============================");
    
                // Action委托类型
                list.ForEach((s) => { Console.WriteLine("姓名:{0},年龄:{1}。", s.Name, s.Age); });
                Console.WriteLine("============================");
    
                // Predicate委托类型
                Student student = list.Find(item => item.Age > 40);
                Console.WriteLine("姓名:{0},年龄:{1}。", student.Name, student.Age);
                Console.WriteLine("============================");
    
                Console.ReadKey();
            }
        }
    
        class Student
        {
            public string Name { get; set; }
    
            public int Age { get; set; }
        }
    }
    View Code

    运行结果:

  • 相关阅读:
    Js中的正则表达式
    js内存泄露的几种情况
    JavaScript的setTimeout与setInterval执行时机
    IE模拟addDOMLoadEvent和jQuery的ready实现
    谈谈JavaScript的异步实现
    在iOS7中修改状态栏字体的颜色
    IOS 疯狂基础之 页面间跳转
    ATL2.1版的CString分析
    翻译: 如何改变MFC应用程序主窗口的类名
    VC5.0中的ATL的一个有趣的bug
  • 原文地址:https://www.cnblogs.com/shaomenghao/p/3364243.html
Copyright © 2011-2022 走看看