C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。

委托(Delegate) 是存有对某个方法的引用的一种引用类型变量 。

现实世界中的委托:

自己动手模式:

委托代码详解-LMLPHP

委托模式:一种类型的委托

委托代码详解-LMLPHP

委托模式:多种类型的委托

委托代码详解-LMLPHP

一、C#内置委托

(1)Action委托:用于调用无参数,无返回值的函数。

class OASystem
{
    public void WelComeChinese()
    {
    	Console.WriteLine("您好,欢迎来到******系统!");
    }
    public void WelComeEnglish()
    {
    	Console.WriteLine("Hello, welcome to the ****** system!");
    }
}
static void Main(string[] args)
{
    //直接调用
    //OASystem oa = new OASystem();
    //oa.WelComeChinese();
    //oa.WelComeEnglish();
    //委托调用
    OASystem oa = new OASystem();
    Action action1 = new Action(oa.WelComeChinese);
    Action action2 = new Action(oa.WelComeEnglish);
    action1();       //或action1.Invoke();
    action2();      //或action2.Invoke();
}

(2)Func委托:一种泛型委托,Func有一系列的重载。

class Calculator
{
    public int Add(int a, int b)
    {
    	return a + b;
    }
    public int Sub(int a, int b)
    {
    	return a - b;
    }
    public int Mul(int a, int b)
    {
    	return a * b;
    }
    public int Div(int a, int b)
    {
    	return a / b;
    }
}
static void Main(string[] args)
{
    //直接调用任意一种运算
    //Calculator cal = new Calculator();
    //int result = cal.Add(1, 2);
    //Console.WriteLine(result);

    Calculator cal = new Calculator();
    Func<int, int, int> func = new Func<int, int, int>(cal.Add);
    int result = func(1, 2);     //或func.Invoke(1, 2);
    Console.WriteLine(result);
}

(3)Predicate:一个传入参数,返回值为bool。

class MyDate
{
    //判断年份是否是闰年
    public bool Is29(int year)
    {
        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
        	return true;
        else
        	return false;
    }
    //判断是否需要工作(星期一到星期五需要工作,周六周日不需要)
    public bool IsWork(DateTime date)
    {
        if ((int)date.DayOfWeek == 0 || (int)date.DayOfWeek == 6)
        	return false;
        else
        	return true;
    }
}
static void Main(string[] args)
{
    //直接调用两个方法
    //bool result = false;
    //MyDate myDate = new MyDate();
    //result = myDate.Is29(2020);
    //Console.WriteLine("闰年:"+result);
    //result = myDate.IsWork(new DateTime(2020, 7, 3));
    //Console.WriteLine("工作:"+result);

    //委托调用两个方法
    bool result = false;
    MyDate myDate = new MyDate();
    Predicate<int> pre1 = new Predicate<int>(myDate.Is29);
    result = pre1(2020); //或result = pre1.Invoke(2020);
    Console.WriteLine("闰年:" + result);
    Predicate<DateTime> pre2 = new Predicate<DateTime>(myDate.IsWork);
    result = pre2(new DateTime(2020, 7, 3)); //或result = pre2.Invoke(new DateTime(2020, 7, 3));
    Console.WriteLine("工作:" + result);
}

二、自定义委托及委托的多播(组播)

class Calculator
{
    public int Num { get; set; }
    public void Add(int n)
    {
    	this.Num += n;
    }
    public void Sub(int n)
    {
    	this.Num -= n;
    }
    public void Mul(int n)
    {
    	this.Num *= n;
    }
    public void Div(int n)
    {
    	this.Num /= n;
    }
}
delegate void ChangeNum(int n);
class Program
{
    static void Main(string[] args)
    {
        //自定义委托调用函数方法
        //Calculator cal = new Calculator();
        //cal.Num = 100;
        //ChangeNum cnAdd = new ChangeNum(cal.Add);
        //cnAdd(10);
        //Console.WriteLine(cal.Num);

        //委托的多播(组播)
        //相同类型的委托被合并,可以创建一个委托被调用时要调用的方法的调用列表
        Calculator cal = new Calculator();
        cal.Num = 100;
        ChangeNum cnAdd = new ChangeNum(cal.Add);
        ChangeNum cnSub = new ChangeNum(cal.Sub);
        ChangeNum cnMul = new ChangeNum(cal.Mul);
        ChangeNum cnDiv = new ChangeNum(cal.Div);

        ChangeNum cn = cnAdd;
        cn += cnMul;
        cn += cnSub;
        cn(50);
        Console.WriteLine(cal.Num);
    }
}

三、委托作为参数传递

手机类:

class Phone  //手机
{
	public string Name { get; set; }  //手机名字
}

包装盒类:

class Box  //包装盒
{
	public Phone MyPhone { get; set; } //手机
}

手机生产工厂类:

class PhoneFactory
{
    public Phone MakeXiaoMi()
    {
        Phone phone = new Phone();
        phone.Name = "小米手机";
        return phone;
    }
    public Phone MakeHuawei()
    {
        Phone phone = new Phone();
        phone.Name = "华为手机";
        return phone;
    }
}

包装生产工厂类:

delegate Phone MakePhone();
class WrapFactory
{
    #region 为每种手机进行包装盒工作-常规写法
    //包装小米手机
    public Box WarpXiaoMi()
    {
        PhoneFactory phoneFactory = new PhoneFactory();
        Phone phone = phoneFactory.MakeXiaoMi();
        Box box = new Box();
        box.MyPhone = phone;
        return box;
    }
    //包装华为手机
    public Box WarpHuawei()
    {
        PhoneFactory phoneFactory = new PhoneFactory();
        Phone phone = phoneFactory.MakeHuawei();
        Box box = new Box();
        box.MyPhone = phone;
        return box;
    }
    #endregion

    #region 将委托作为参数
    public Box WarpPhone(MakePhone mp)
    {
        Phone phone = mp();
        Box box = new Box();
        box.MyPhone = phone;
        return box;
    }
    #endregion
}

Main函数:

static void Main(string[] args)
{
    #region 生产并包装两个手机-常规写法
    //WrapFactory wrapFactory = new WrapFactory();
    //Box box1 = wrapFactory.WarpXiaoMi();
    //Console.WriteLine(box1.MyPhone.Name + "生产及包装已经完成!");
    //Box box2 = wrapFactory.WarpHuawei();
    //Console.WriteLine(box2.MyPhone.Name + "生产及包装已经完成!");
    #endregion

    #region 生产并包装两个手机-委托作为参数
    PhoneFactory phoneFactory = new PhoneFactory();
    MakePhone makeXiaomi = new MakePhone(phoneFactory.MakeXiaoMi);
    MakePhone makeHuawei = new MakePhone(phoneFactory.MakeHuawei);
    WrapFactory wrapFactory = new WrapFactory();
    Box box1 = wrapFactory.WarpPhone(makeXiaomi);
    Console.WriteLine(box1.MyPhone.Name + "生产及包装已经完成!");
    Box box2 = wrapFactory.WarpPhone(makeHuawei);
    Console.WriteLine(box2.MyPhone.Name + "生产及包装已经完成!");
    #endregion
}

四、利用委托实现匿名函数回调

delegate void CallBackDelegate(int score);
class Student
{
    public string Name { get; set; } //姓名
    public string Mail { get; set; } //邮箱
    public int Score { get; set; } //分数
    public void Exam(CallBackDelegate callback = null)
    {
        Console.WriteLine("请填写姓名:");
        this.Name = Console.ReadLine();
        Console.WriteLine("请填写邮箱:");
        this.Mail = Console.ReadLine();

        Random rnd = new Random();
        this.Score = rnd.Next(0, 101);
        Console.WriteLine("该学生面试成绩为:" + this.Score);
        if (callback != null)
        callback(this.Score);
    }
}
static void Main(string[] args)
{
    //Student stu = new Student();
    //CallBackDelegate myDelegate = delegate (int score)
    //{
    //    if (score >= 60)
    //        Console.WriteLine("已经给" + stu.Name + "的邮箱:"
    //            + stu.Mail + "发送了录用入职邀请!");
    //    else
    //        Console.WriteLine("很遗憾,我们不能录用您!");
    //};
    //stu.Exam();   //无参数调用
    //stu.Exam(myDelegate);  //有参数调用

    Student stu = new Student();
    //stu.Exam();
    //或
    stu.Exam((score) =>
    {
        if (score >= 60)
        	Console.WriteLine("已经给" + stu.Name + "的邮箱:" +
        		stu.Mail + "发送了录用入职邀请!");
        else
        	Console.WriteLine("很遗憾,我们不能录用您!");
    });
}

五、委托与事件

class EventTest
{
    public delegate void MyEventHandler();
    public event MyEventHandler ValueChanged;

    private int value;
    public int Value
    {
        get
        {
        	return value;
        }
        set
        {
            ValueChanged();
            this.value = value;
        }
    }
}
static void Main(string[] args)
{
    EventTest et = new EventTest();
    et.ValueChanged += new EventTest.MyEventHandler(myEventFunction);
    et.Value = 100;
    et.Value = 200;
}
public static void  myEventFunction()
{
	Console.WriteLine("value值在发生改变!");
}

本文来自博客园,作者:農碼一生,转载请注明原文链接:https://www.cnblogs.com/wml-it/p/16105580.html


技术的发展日新月异,随着时间推移,无法保证本博客所有内容的正确性。如有误导,请大家见谅,欢迎评论区指正!
个人开源代码链接,欢迎点亮:
GitHub:https://github.com/ITMingliang
Gitee:https://gitee.com/mingliang_it
GitLab:https://gitlab.com/ITMingliang
进开发学习交流群:
委托代码详解-LMLPHP
04-06 11:28