.NET高级技术_02委托、lambda、事件

一:委托的概念

委托是一种可以指向方法的数据类型,可以声明委托类型变量。

声明委托的方式:delegate 返回值类型 委托类型名(参数)
比如:delegate void MyDel(int i);

注意这里的除了前面的delegate,剩下部分和声明一个函数一样,但是MyDel不是函数名,而是委托类型名。

如何创建委托类型的对象:
MyDel sp = new MyDel (SayHello); //SayHello需要和MyDel的参数返回值一样;sp这个委托变量就指向SayHello这个方法。
注意不要写成new Mydel (SayHello())因为加上()就是调用方法了。

简化的方法:MyDel sp = SayHello;
编译器会给搞成new Mydel(SayHello),反编译看看。注意不要写成MyDel sp = SayHello();

委托的使用:委托变量之间可以互相赋值,就是一个传递指向方法的过程;sp()就是调用指向的方法,如果有参数就传递参数。

委托是引用类型,可以为null,如果委托变量是null,那么如果调用的话,就会抛出NullReferenceException。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;

namespace NS
{
    public delegate void MyDel1(int i);
    public delegate int MyDel2(int i, string s);
    public delegate string MyDel3();

    internal class Program
    {
        static void Main(string[] args)
        {
            不能写成new MyDel(M1()); 因为()代表调用方法
            //MyDel1 d1 = new MyDel1(M1);  //声明一个MyDel类型的变量d1,new MyDel(M1)创建一个指向M1方法的委托对象。
            //Console.WriteLine(d1);
            //d1(10);  //调用d1指向的方法
            //MyDel2 d2 = new MyDel2(M2);
            //int i1 = d2(10, "abc");
            //Console.WriteLine("i1 = " + i1);

            //MyDel3 d3 = new MyDel3(M3);
            //Console.WriteLine(d3);
            //Console.WriteLine(d3());  //加括号和不加括号的区别!
            //d3 = new MyDel3(M4);
        

            MyDel3 d3 = M3;  //等价于MyDel3 d3 = new MyDel3(M3);
            Console.WriteLine(d3());
            Console.ReadLine();
        }

        static void M1(int i)
        {
            Console.WriteLine("i = " + i);
        }

        static int M2(int i, string str)
        {
            return i + 10;
        }

        static string M3()
        {
            return "M3";
        }

        static string M4()
        {
            return "M4";

        }
    }
}

二:委托的应用

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;

namespace NS
{
    delegate bool CompareFunc(object obj1, object obj2);

    internal class Program
    {
        static void Main(string[] args)
        {
            //int[] objs = new int[] { 1, 2, 4, 4, 2, 1, 2, 3 };  //int[]无法直接转换为object[]
            //object[] objs = { 1, 2, 4, 4, 2, 1, 2, 3 };
            object[] objs = { 1.1, 2.2, 4.3, 4.4, 2.5, 1.6, 2.7, 3.8 };
            //object o1 = GetMax(objs, CompareInt);
            object o1 = GetMax(objs, new CompareFunc(Compare));
            Console.WriteLine(o1);

            Person p1 = new Person();
            p1.Name = "lilei";
            p1.Age = 10;

            Person p2 = new Person();
            p2.Name = "hanmeimei";
            p2.Age = 20;

            Person p3 = new Person();
            p3.Name = "polly";
            p3.Age = 30;

            Person[] sites = new Person[] { p1, p2, p3 };
            object obj1 = GetMax(sites, ComparePerson);
            Person person = obj1 as Person;
            Console.WriteLine(person.ToString()) ;
            Console.ReadLine();
        }

        static bool Compare(object obj1, object obj2)
        {
            dynamic first = obj1, second = obj2;
            return first > second;
        }

        static bool ComparePerson(object obj1, object obj2)
        {
            Person p1 = obj1 as Person;
            Person p2 = obj2 as Person;
            return p1.Age > p2.Age;
        }

        static object GetMax(object[] nums, CompareFunc func)
        {
            object max = nums[0];
            for (int i = 0; i < nums.Length; i++)
            {
                if (func(nums[i], max))
                {
                    max = nums[i];
                }
            }
            return max;
        }
    }

    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }

        public override string ToString()
        {
            return "Name = " + Name + ", Age = " + Age;
        }
    }
}
namespace NS
{
    delegate T MyDel<T>(T t);
    internal class Program
    {
        static void Main(string[] args)
        {
            MyDel<int> mydel1 = Func1;
            Console.WriteLine(mydel1(20));
            Console.ReadLine();
        }

        static int Func1(int i)
        {
            return i + 10;
        }
    }
}

三:Func、Action

.Net中内置两个泛型委托Func、Action(在“对象浏览器”的mscorlib的System下),日常开发中基本不用自定义委托类型了。
Func是有返回值的委托;Action是没有返回值的委托。
测试一下用Func、 Action代替之前的委托。

namespace NS
{
    //delegate void Dele1();
    internal class Program
    {
        static void Main(string[] args)
        {
            //Dele1 d1 = Func1;
            Action action1 = Func1;
            action1();
            Func<int, int, bool> func1 = CompareInt;
            Console.WriteLine(func1(3, 5));
            Console.ReadLine();
        }

        static void Func1()
        {
            Console.WriteLine("Func1");
        }
        static bool CompareInt(int i1, int i2)
        {
            return i1 > i2;
        }
    }
}

四:匿名方法

使用Delegate的时候很多时候没必要使用一个普通的方法,因为这个方法只有这个Delegate会用,并且只用一次,这时候使用匿名方法最合适。

匿名方法就是没有名字的方法。定义语法:MyDelegate p = delegate(int s){s=10;};

使用匿名方法改造GetMax方法:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;

namespace NS
{
    delegate bool Mydele1(int i, string s);
    delegate bool CompareFunc(object obj1, object obj2);
    internal class Program
    {
        static void Main(string[] args)
        {
            Mydele1 d1 = Func1;
            Mydele1 d2 = delegate (int i, string str)
            {
                Console.WriteLine("i = " + i + ", str = " + str);
                return true;
            };
            bool b1 = d2(5, "lilei");
            Console.WriteLine(b1);

            object[] objs = new object[] { 1, 2, 4, 4, 2, 1, 2, 3 };  //int[]无法直接转换为object[]
            CompareFunc f1 = delegate (object obj1, object obj2)
            {
                dynamic first = obj1, second = obj2;
                return first > second;
            };
            object obj = GetMax(objs, f1);
            Console.WriteLine(obj);
            Console.ReadLine();
        }

        static bool Func1(int i, string str)
        {
            Console.WriteLine("i = " + i + ", str = " + str);
            return true;
        }

        static object GetMax(object[] nums, CompareFunc func)
        {
            object max = nums[0];
            for (int i = 0; i < nums.Length; i++)
            {
                if (func(nums[i], max))
                {
                    max = nums[i];
                }
            }
            return max;
        }
    } 
}

五:lambda表达式

函数式编程,在Entity framework编程中用的很多

1、Action a1 = delegate(int i) { Console.WriteLine(i); };
可以简化成(=>读作goes to)
Action a2 = (int i) => { Console.WriteLine(i); };

2、可以省略参数类型(编译器会自动根据委托类型推断)。
Action a3 = (i) => { Console.WriteLine(i); };
如果只有一个参数还可以省略参数的小括号(多个参数不行)
Action a4 = i => { Console.WriteLine(i); };

3、如果委托有返回值,并且方法体只有一行代码,这一行代码还是返回值,那么就可以连方法的大括号和return都省略:
Func<int, int, string> f1 = delegate(int i, int j) { return “结果是” + (i + j); };
Func<int,int,string> f2= (i,j)=>“结果是”+(i+j);

4、普通匿名类型也是一样用lambda表达式。

internal class Program
{
    static void Main(string[] args)
    {
        Action<int> a1 = delegate (int i) { Console.WriteLine(i); };
        Action<int> a2 = (int i) => { Console.WriteLine(i); };
        Action<int> a3 = i => { Console.WriteLine(i); };

        Func<string, int, bool> f1 = delegate (string s, int i) { return true; };
        Func<string, int, bool> f2 = (string s, int i) => { return true; };
        Func<string, int, bool> f3 = (s, i) => { return true; };
        Func<string, int, bool> f4 = (s, i) => true;

        Console.ReadLine();
    }
}
namespace NS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            int[] nums = new int[] { 1, 2, 4, 4, 2, 1, 2, 3 };
            //int i_max = GetMax(nums, CompareInt);
            //int i_max = GetMax(nums, delegate (int i1, int i2) { return i1 > i2; });
            int i_max = GetMax(nums, (i1, i2) => i1 > i2);
            Console.WriteLine(i_max);

            Person p1 = new Person();
            p1.Name = "lilei";
            p1.Age = 10;

            Person p2 = new Person();
            p2.Name = "hanmeimei";
            p2.Age = 20;

            Person p3 = new Person();
            p3.Name = "polly";
            p3.Age = 30;

            Person[] sites = new Person[] { p1, p2, p3 };

            Person p = GetMax<Person>(sites, (p1, p2) => p1.Age > p2.Age);
            Console.WriteLine(p);
            Console.ReadLine();
        }

        static bool CompareInt(int i1, int i2)
        {
            return i1 > i2;
        }

        static T GetMax<T>(T[] objs, Func<T, T, bool> compareFunc)
        {
            T max = objs[0];
            for (int i = 0; i < objs.Length; i++)
            {
                if (compareFunc(objs[i], max))
                {
                    max = objs[i];
                }
            }
            return max;
        }
    }

    class Person
    {
        public Person()
        {
            
        }

        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public string Name { get; set; }
        public int Age { get; set; }

        public override string ToString()
        {
            return "Name = " + Name + ", Age = " + Age;
        }
    }
}
namespace NS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            int[] nums = new int[] { 1, 2, 4, 4, 2, 1, 2, 3 };
            //IEnumerable<int> list = nums.MyWhere(i => i > 2);
            IEnumerable<int> list = nums.MyWhere(i => i % 2 == 0);
            foreach (var item in list)
            {
                Console.WriteLine(item);
            }

            string[] strs = new string[] { "tom", "jim", "lily", "hanmeimei" };
            foreach (var name in strs.MyWhere(s => s.Contains("m")))
            {
                Console.WriteLine(name);
            }
            Console.ReadLine();
        }
    }

    public static class JiHeExt
    {
        public static IEnumerable<T> MyWhere<T>(this IEnumerable<T> data, Func<T, bool> func)
        {
            List<T> resultList = new List<T>();
            //foreach()面试题:什么样的对象可以使用foreach遍历?
            //实现了IEnumreable接口。List,数组等都实现了IEnumerable接口
            foreach (var item in data)
            {
                if (func(item))
                {
                    resultList.Add(item);
                }
            }
            return resultList;
        }
    }
}

六:集合常用扩展方法

Where(支持委托):是对数据按照lambda表达式进行过滤。

Select(支持委托):是对集合中的数据进行处理,生成一个新的集合,集合长度和原始集合长度一致。

Max、Min、Sum、Average

OrderBy

namespace NS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            List<int> list = new List<int>() { 3, 9, 8, 16, 90 };
            //IEnumerable<int> data = list.Where(x => x > 10);
            //IEnumerable<int> data = list.Select(x => x * 10);
            IEnumerable<string> data = list.Select(x => "hello: " + x);
            Console.WriteLine(data.GetType());  //返回实现该接口的类
            foreach (var item in data)
            {
                Console.WriteLine(item);
            }

            int max = list.Max();
            int min = list.Min();
            int sum = list.Sum();
            double average = list.Average();
            Console.WriteLine("max = " + max + ", min = " + min + ", sum = " + sum + ", average = " + average);

            Console.WriteLine("====================================");

            foreach (var item in list.OrderBy(i => i))
            {
                Console.WriteLine(item);
            }

            Console.WriteLine("====================================");

            Person p3 = new Person();
            p3.Name = "polly";
            p3.Age = 30;

            Person p1 = new Person();
            p1.Name = "lilei";
            p1.Age = 10;

            Person p2 = new Person();
            p2.Name = "hanmeimei";
            p2.Age = 20;

            Person[] sites = new Person[] { p1, p2, p3 };

            int age_sum1 = sites.Sum(p => p.Age);
            int age_sum2 = sites.MySum(p => p.Age);
            int age_sum3 = sites.MySum(p => p.Name.Length);

            Console.WriteLine(age_sum1);
            Console.WriteLine(age_sum2);
            Console.WriteLine(age_sum3);

            //foreach (var item in sites.OrderBy(p => p.Age))
            foreach (var item in sites.OrderBy(p => p.Name.Length))
            {
                Console.WriteLine(item);
            }

            List<Person> ps1 = sites.OrderBy(p => p.Age).ToList();
            Person[] ps2 = sites.OrderBy(p => p.Age).ToArray();
            List<Person> ps3 = sites.ToList();
            Person[] ps4 = ps3.ToArray();

            Console.ReadLine();
        }
    }

    class Person
    {
        public Person()
        {

        }

        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public string Name { get; set; }
        public int Age { get; set; }

        public override string ToString()
        {
            return "Name = " + Name + ", Age = " + Age;
        }
    }

    public static class MyEx
    {
        public static int MySum<T>(this IEnumerable<T> data, Func<T, int> func)
        {
            int sum = 0;
            foreach (var item in data)
            {
                sum += func(item);
            }
            return sum;
        }
    }
}

First:获取第一个,如果一个都没有则异常
FirstOrDefault:获取第一个,如果一个都没有则返回默认值
Single:获取唯一一个,如果没有或者有多个则异常
SingleOrDefault:获取唯一一个,如果没有则返回默认值,如果有多个则异常
ToList、ToArray

namespace NS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string[] strs1 = { };
            string[] strs2 = { "lilei" };
            string[] strs3 = { "lilei", "hanmeimei" };

            List<int> list1 = new List<int>();
            //int i = list1.First();
            Console.WriteLine(list1.FirstOrDefault());

            //string s1 = strs1.First();  //获取集合中的第一个元素,如果一个元素都没有,则抛异常
            Console.WriteLine(strs2.First());
            string s1 = strs1.FirstOrDefault();  //获取集合中的第一个元素,如果一个元素都没有,则返回类型的默认值

            string s2 = strs2.Single();  //获取集合中的唯一一个元素,如果没有元素或者有不止一个元素,则抛异常
            string s3 = strs2.SingleOrDefault();  //获取集合中的唯一一个元素,如果没有元素则返回null,
                                                  //如果有多个元素,则抛异常
            Console.WriteLine("====================================");

            List<int> list2 = new List<int>() { 3, 9, 8, 90, 10, 35 };
            foreach (var item in list2.Where(i => i > 7).OrderBy(i => i).Select(i => i + 10))
            {
                Console.WriteLine(item);
            }
            int max = list2.Where(i => i > 7).Max();
            Console.WriteLine(max);

            Console.ReadLine();
        }
    }

    class Person
    {
        public Person()
        {

        }

        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public string Name { get; set; }
        public int Age { get; set; }

        public override string ToString()
        {
            return "Name = " + Name + ", Age = " + Age;
        }
    }

    public static class MyEx
    {
        public static int MySum<T>(this IEnumerable<T> data, Func<T, int> func)
        {
            int sum = 0;
            foreach (var item in data)
            {
                sum += func(item);
            }
            return sum;
        }
    }
}

七:委托的组合

委托对象可以“+相加”,调用组合后的新委托对象会依次调用被组合起来的委托:MyDel m5 = m1+m2+m3;
组合的委托必须是同一个委托类型。

委托的“-”则是从组合委托中把委托移除;

委托如果有返回值,则有一些特殊。委托的组合一般是给事件用的,用普通的委托的时候很少用。

namespace NS
{
    delegate void MyDel(int i);
    internal class Program
    {
        static void Main(string[] args)
        {
            MyDel d1 = F1;  //MyDel d1 = new MyDel(F1);
            MyDel d2 = F2;
            MyDel d3 = F3;
            MyDel d4 = d1 + d2 + d3;
            MyDel d5 = new MyDel(F1) + new MyDel(F2) + new MyDel(F3);
            d4(10);
            d4 = d4 - d2;
            Console.WriteLine("第二次调用d4");
            d4(20);
            Console.ReadLine();
        }

        static void F1(int i)
        {
            Console.WriteLine("我是f1:" + i);
        }

        static void F2(int i)
        {
            Console.WriteLine("我是f2:" + i);
        }

        static void F3(int i)
        {
            Console.WriteLine("我是f3:" + i);
        }
    } 
}

八:事件

案例:定义一个Person类,定义一个监听年龄变化的事件,当本命年的时候祝贺一下。触发事件的地方要判断一下是不是事件null。

事件语法:event Mydelegate mdl;

加了event关键字实现事件机制的好处:用了event事件,不可以修改事件已经注册的值;不可以冒充进行事件通知了。只能+=、-=!

namespace NS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person();
            p1.OnBenMingNian += BMN;  //方法的参数返回值要和事件的委托一致\
            p1.OnBenMingNian += BMN2;
            p1.OnBenMingNian = null;
            p1.Age = 5; 
            Console.WriteLine(p1.Age);
            p1.Age = 24;
            Console.WriteLine(p1.Age);
            Console.ReadLine();
        }

        static void BMN()
        {
            Console.WriteLine("BMN()到了本命年了!");
        }

        static void BMN2()
        {
            Console.WriteLine("BMN2()到了本命年了!");
        }
    }

    class Person
    {
        private int _Age;

        public int Age
        {
            get { return _Age; }
            set
            {
                _Age = value;
                if (_Age % 12 == 0)
                {
                    if (OnBenMingNian != null)
                    {
                        OnBenMingNian();
                    }
                }
            }
        }

        //public event Action OnBenMingNian;  //event 委托类型事件的名字;

        public Action OnBenMingNian;  //event 委托类型事件的名字;
    }
}

九:委托和事件的总结

委托的作用:占位,在不知道将来要执行的方法的具体代码时,可以先用一个委托变量来代替方法调用(委托的返回值,参数列表要确定)。在实际调用之前,需要为委托赋值,否则为null。

事件的作用:事件的作用与委托变量一样,只是功能上比委托变量有更多的限制。(比如:1.只能通过+=或-=来绑定方法(事件处理程序)2.只能在类内部调用(触发)事件。)

(面试题)事件和委托的关系:事件由一个私有的委托变量和add_***和remove_***方法组成;
事件的非简化写法:声明一个私有的委托变量和add、remove方法。

委托和事件的区别和关系

一种错误的说法“事件是一种特殊的委托”,事件是由一个私有委托和add、remove两个方法组成的。
委托用的比较多,事件只有开发WinForm、WPF的时候用的才比较多。

事件、索引器、属性本质上都是方法。

(面试题)接口中可以定义什么?
答:接口中只可以定义方法。接口中也可以定义“事件、索引器、属性”,因为他们本质上也都是方法。

namespace NS
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person();
            p1.OnBenMingNian += BMN;  //方法的参数返回值要和事件的委托一致\
            p1.OnBenMingNian += BMN2;
            //p1.OnBenMingNian = null;
            p1.Age = 5; 
            Console.WriteLine(p1.Age);
            p1.Age = 24;
            Console.WriteLine(p1.Age);
            Console.ReadLine();
        }

        static void BMN()
        {
            Console.WriteLine("BMN()到了本命年了!");
        }

        static void BMN2()
        {
            Console.WriteLine("BMN2()到了本命年了!");
        }
    }

    class Person
    {
        private int _Age;

        public int Age
        {
            get { return _Age; }
            set
            {
                _Age = value;
                if (_Age % 12 == 0)
                {
                    //if (OnBenMingNian != null)
                    //{
                    //    OnBenMingNian();
                    //}
                    if (_OnBenMingNian != null)
                    {
                        _OnBenMingNian();
                    }
                }
            }
        }

        //public event Action OnBenMingNian;  //event 委托类型事件的名字;
        //public Action OnBenMingNian;  //加上event就是事件,不加event就是委托;

        //事件是由私有的委托+add+remove组成
        private Action _OnBenMingNian;
        public event Action OnBenMingNian
        {
            add
            {
                this._OnBenMingNian += value;
            }

            remove
            {
                this._OnBenMingNian -= value;
            }
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值