【学习笔记】委托、匿名方法、Lambda表达式和事件

一、委托

1、概念

  委托是一个特殊的类,其保存的是一个或者多个方法,这些方法具有相同的签名和返回类型。

2、委托使用

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var test = new Test();

            //var myDele = new MyDelegate(t.DoInstance); //声明委托方式1
            MyDelegate myDele = Test.DoStatic; //声明委托方式2
            myDele += test.DoInstance; //添加方法
            myDele += Test.DoStatic;
            myDele -= Test.DoStatic; //移除方法
            //调用委托,委托调用与方法调用一致,需要传递实参,当委托调用时,其所关联的方法都将被顺序调用
            myDele("Hello World");

            Console.ReadKey();
        }
    }

    /// <summary>
    /// 声明委托
    /// </summary>
    /// <param name="msg"></param>
    public delegate void MyDelegate(string msg);

    /// <summary>
    /// 测试类
    /// </summary>
    public class Test
    {
        //静态方法
        public static void DoStatic(string msg)
        {
            Console.WriteLine($"DoStatic:{msg}");
        }

        //实例方法
        public void DoInstance(string msg)
        {
            Console.WriteLine($"DoInstance:{msg}");
        }
    }
}

3、匿名方法

  方法只会被使用一次用来初始化委托,无需创建具名的方法,系统自动创建当前类的私有静态方法。

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //匿名方法用来初始化委托
            MyDelegate myDele = delegate (string msg)
            {
                return $"Delegate:{msg}";
            };
            var retMsg = myDele("Hello World");

            Console.WriteLine(retMsg);
            Console.ReadKey();
        }
    }

    /// <summary>
    /// 声明委托
    /// </summary>
    public delegate string MyDelegate(string msg);
}

4、Lambda表达式

  用来简化匿名方法,简化过程如下:

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //匿名方法用来初始化委托
            MyDelegate myDele = delegate (string msg)
            {
                return $"Delegate:{msg}";
            };
            //1、去掉delegate,在参数括号后面添加“=>”
            myDele = (string msg) => { return $"Delegate:{msg}"; };
            //2、参数类型可以去掉
            myDele = (msg) => { return $"Delegate:{msg}"; };
            //3、如果参数个数只有1个,可以去掉“()”
            myDele = msg => { return $"Delegate:{msg}"; };
            //4、如果方法体内部只有一个return语句,去掉“return”和“{}”
            myDele = msg => $"Delegate:{msg}";

            var retMsg = myDele("Hello World");
            Console.WriteLine(retMsg);
            Console.ReadKey();
        }
    }

    /// <summary>
    /// 声明委托
    /// </summary>
    public delegate string MyDelegate(string msg);
}

5、事件

  事件是类的成员之一,它封装了委托类型的变量,在类的外部只允许使用“+=”和“-=”操作符进行事件的注册和注销。声明一个事件不过类似于声明一个进行了封装的委托类型的变量而已。

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var test = new Test();
            var eventTest = new EventTest();
            eventTest.MyEvent += test.DoInstance;
            eventTest.MyEvent += Test.DoStatic;
            eventTest.MyEvent -= test.DoInstance;
            eventTest.OnEventHangler("Hello World"); //在合适的地方调用

            Console.ReadKey();
        }
    }

    /// <summary>
    /// 声明委托
    /// </summary>
    /// <param name="msg"></param>
    public delegate void MyDelegate(string msg);

    /// <summary>
    /// 测试类
    /// </summary>
    public class Test
    {
        //静态方法
        public static void DoStatic(string msg)
        {
            Console.WriteLine($"DoStatic:{msg}");
        }

        //实例方法
        public void DoInstance(string msg)
        {
            Console.WriteLine($"DoInstance:{msg}");
        }
    }

    /// <summary>
    /// 事件测试类
    /// </summary>
    public class EventTest
    {
        /// <summary>
        /// 声明事件
        /// </summary>
        public event MyDelegate MyEvent;

        /// <summary>
        /// 定义激活事件的方法(在类的外部激活)
        /// </summary>
        public virtual void OnEventHangler(string msg)
        {
            //事件只能在声明事件所在类的内部进行调用
            MyEvent?.Invoke(msg);
        }
    }
}

6、逆变和协变

  1)、二者只使用与泛型委托和泛型接口。

  2)、协变:由子类方向 向 父类方向 转变,用out关键字,T类型只能用于返回值。

  3)、逆变:由父类方向 向 子类方向 转变,用in关键字,T类型只能用于传入参数。

7、系统内置的泛型委托

  1)、Action泛型委托:0-16个传入参数,无返回值。

public delegate void Action();

public delegate void Action<in T>(T obj);

public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);

public delegate void Action<in T1, in T2, in T3>(T1 arg1, T2 arg2, T3 arg3);

......

  2)、Func泛型委托:0-16个传入参数,一个返回值。

public delegate TResult Func<out TResult>();

public delegate TResult Func<in T, out TResult>(T arg);

public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);

public delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 arg1, T2 arg2, T3 arg3);

public delegate TResult Func<in T1, in T2, in T3, in T4, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);

......

  3)、Predicate泛型委托:1个传入参数,返回bool类型。

public delegate bool Predicate<in T>(T obj);

  4)、Comparison泛型委托:1个类型传入参数,接受两个同类型参数用于比较,返回int类型。

public delegate int Comparison<in T>(T x, T y);

猜你喜欢

转载自www.cnblogs.com/xyh9039/p/12549465.html