C#委托

委托

方法签名

方法签名包括:1.返回类型 2.参数列表 3.方法名称

关键字:Delegate

语法:

//声明
public delegate void GreetingDelegate(string name);
//使用
 public void GreetPeople(string name,GreetingDelegate makeGreeting)
        {
            makeGreeting(name);
        }

Delegate是一个类,在任何可以声明类的地方都可以声明委托

//定义委托,它定义了可以代表的方法的类型
    public delegate void GreetingDelegate(string name);
    class Program
    {
        public static void EnglishGreeting(string name)
        {
            Console.WriteLine($"Morning,{name}");
        }
        public static void ChineseGreeting(string name)
        {
            Console.WriteLine($"早上好,{name}");
        }
        //注意此方法,它接受一个GreetingDelegate类型的方法作为参数
        public static void GreetPeople(string name, GreetingDelegate makeGreeting)
        {
            makeGreeting(name);
        }
        static void Main(string[] args)
        {
            GreetPeople("Jimmy Zhang", EnglishGreeting);
            GreetPeople("张子阳", ChineseGreeting);
        }
    }

委托总结

委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态的赋给参数的做法,可以避免在程序中大量使用if-else(switch)语句,同时使得程序具有更好的扩展性。

使用变量传递参数
 static void Main(string[] args)
        {
            string name1, name2;  //声明
            name1 = "Jimmy Funy";  //赋值
            name2 = "王小毛";     //赋值


            GreetPeople(name1, EnglishGreeting);
            GreetPeople(name2, ChineseGreeting);
        }
GreetingDelegate delegate1,delegate2;  //声明
            delegate1 = EnglishGreeting;        //赋值
            delegate2 = ChineseGreeting;        //赋值

            GreetPeople("Jimmy Funy", delegate1);
            GreetPeople("王小毛", delegate2);
委托可以将多个方法赋给同一个委托,或者说将多个方法绑定到用一个委托,当调用这个委托的时候,将依次调用其所绑定的方法
		   GreetingDelegate delegate1;
            delegate1 = EnglishGreeting;
            delegate1 += ChineseGreeting;       //绑定第二个方法
            GreetPeople("Jimmy Funy", delegate1);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E40E8TTh-1620098690373)(F:\S2\笔记\img\委托.png)]

跳过GreetPeople()方法,通过委托直接调用EnglishGreeting()ChineseGreeting()并且与之传参
		   GreetingDelegate delegate1;
            delegate1 = EnglishGreeting;        //先给委托类型的变量赋值
            delegate1 += ChineseGreeting;       //给此委托变量再绑定一个方法
            //将先后调用EnglishGreeting与ChinaeseGreeting方法
            delegate1("Jimmy Funy");		

第一次用的“=”是赋值的语法,第二次用的“+=”是绑定的语法。如果第一次就使用“+=”,将出现“使用了未赋值的局部变量”的编译错误。

 GreetingDelegate delegate1 = new GreetingDelegate(EnglishGreeting);

赋初始值

能使用+=绑定一个方法,同样可以用-=取消一个方法的绑定
		   GreetingDelegate delegate1 = new GreetingDelegate(EnglishGreeting);
            delegate1 += ChineseGreeting;    //给此委托变量再绑定一个方法

            //将先后调用EnglishGreeting与ChinaeseGreeting方法
            GreetPeople("Jimmy Funy",delegate1);
            Console.WriteLine();

            delegate1 -= EnglishGreeting;   //取消对EnglishGreeting方法的绑定
            //将仅调用ChineseGreeting
            GreetPeople("王小毛", delegate1);

事件

事件是对委托的封装

语法:访问修饰符 event 委托类型 事件名:

    //新建的类
    public class GreetingManager
    {
        //声明事件
        public event GreetingDelegate MakeGreet;
        public void GreetPeople(string name)
        {
            MakeGreet(name);
        }

通过反编译代码能明确:MakeGreet事件确实是一个GreetingDelegate类型的委托,只不过不管是不是声明为Public,它总是被声明为private。另外,它还有两个方法分别是add_MakeGreeet和remove_MakeGreet,两个方法分别对应了“+=“和”-=“,而这两个的访问权限取决于声明事件的访问修饰符

事件限制类型的能力

事件应该由事件发布者触发,而不应该由事件的客户端(客户程序)来触发

 //定义委托
    public delegate void NumberChangedEventHandler(int count);
    //事件发布者类
    public class Publishser
    {
        private int count;
        //声明委托变量
       // public NumberChangedEventHandler NumberChanged;

        //声明一个事件
        public event NumberChangedEventHandler NumberChanged;
        public void DoSomething()
        {
            if (NumberChanged != null)  //触发事件
            {
                count++;
                NumberChanged(count);
            }
        }
    }
 //事件订阅者类
    public class Subscriber
    {
        public void OnNumberChanged(int count)
        {
            Console.WriteLine($"Subscriber notified:count = {count}");
        }
    }
 static void Main(string[] args)
        {
            Publishser pub = new Publishser();  //发布者对象
            Subscriber sub = new Subscriber();  //订阅者对象
            pub.NumberChanged += new NumberChangedEventHandler(sub.OnNumberChanged);
            pub.DoSomething();  //应该通过DoSomething()触发事件
            //pub.NumberChanged(100);   //有委托可以被直接调用,对委托变量使用的不恰当,使用事件后将会报错
         }

事件只能为事件发布者在其本身的某个行为中触发,当使用了event关键字之后委托变量成为事件,直接在调用事件的方法是被禁止的

就像我们要定义一个数字类型,我们会用int而不是使用object一样,给予对象过多的能力并不见得是一件好事,应该是越合适越好。

尽管直接使用委托变量通常不会有什么问题,但它给了客户端不应具有的能力,而使用事件,可以限制这一能力,更精准的对类型进行封装。

约定:订阅事件的方法的命名,通常为"On 事件名"比如OnNumberChanged

Observer设计模式(观察者模式)

设计者模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新

主要包括两类对象:

  • Subject:监视对象,它往往包含着其他对象所感兴趣的内容。
    • 热水器类就是一个监视对象,当温度快到100时,会不断把数据发给监视它的对象。
  • Observer:监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采用相应的行动
    • 警报器类和显示器类,它们采取的行动分别是发出警报和显示水温
//热水器类
    public class Heater
    {
        private int temperature;  //温度
        //创建委托
        public delegate void BoilHeadler(int param);
        //定义事件
        public event BoilHeadler BoilEvent;
        //烧水
        public void BoilWater()
        {
            for (int i = 0; i < 100; i++)
            {
                temperature = i;
                if (temperature > 95)
                {
                    if (BoilEvent != null)
                    {
                        BoilEvent(temperature); //调用所有注册对象的方法
                    }
                }
            }
      
//警报器类
    public class Alarm
    {
        //发出语言警报方法
        public void MakeAlert(int param)
        {
            Console.WriteLine($"警报:嘀嘀嘀,水已经{param}度了");
        }
    }
  //显示器类
    public class DisPlay
    {
        //显示温度方法
        public static void ShowMsg(int param)
        {
            Console.WriteLine($"提示:水已烧开,当前温度:{param}度");
        }
    }

事情的发生顺序

  • 警报器和显示器告诉热水器,它对它的温度比较感兴趣(注册)
  • 热水器知道后保留对警报器和显示器的引用
  • 热水器进行烧水这一动作,当水温超过95度时,通过对警报器和显示器的引用,自动调用警报器的MakeAlert()方法和显示器的ShowMsg()方法
 static void Main(string[] args)
        {
            Heater heater = new Heater();
            Alarm alarm = new Alarm();
            heater.BoilEvent += alarm.MakeAlert;  //注册方法
            heater.BoilEvent += (new Alarm()).MakeAlert;  //给匿名对象注册方法
            heater.BoilEvent += DisPlay.ShowMsg;    //注册静态方法
            heater.BoilWater();   //烧水,会自动调用注册过的对象的方法
        }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-szw8Q1Gc-1620098690378)(F:\S2\笔记\img\Observer设计.png)]

ent += alarm.MakeAlert; //注册方法
heater.BoilEvent += (new Alarm()).MakeAlert; //给匿名对象注册方法
heater.BoilEvent += DisPlay.ShowMsg; //注册静态方法
heater.BoilWater(); //烧水,会自动调用注册过的对象的方法
}


[外链图片转存中...(img-szw8Q1Gc-1620098690378)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值