19-委托

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

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

现实世界中的委托:

自己动手模式:


0001.PNG

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


0002.PNG

委托模式:多种类型的委托
0003.PNG

一、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值在发生改变!");
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容