c# 委托和事件

一、什么是委托
1.1官方解释
委托是一种定义方法签名的类型。当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联。您可以通过委托实例调用方法。
1.2个人理解
委托就是执行方法(函数)的一个类。
事件是一种特殊的委托。
二、如何申明委托
2.1 delegate
        public delegate int TestDelegate(int x, int y);
2.2 Action
       Action是无返回值的泛型委托。
       Action 表示无参,无返回值的委托
       Action<int,string> 表示有传入参数int,string无返回值的委托

2.3 Func
Func是有返回值的泛型委托
Func<int> 表示无参,返回值为int的委托

Func<object,string,int> 表示传入参数为object, string 返回值为int的委托


2.4 predicate
predicate 是返回bool型的泛型委托
predicate<int> 表示传入参数为int 返回bool的委托。

2.5 四者之间的区别
Delegate至少0个参数,至多32个参数,可以无返回值,也可以指定返回值类型
Action至少1个参数,至多4个参数,无返回值,
Func至少0个参数,至多4个参数,根据返回值泛型返回。必须有返回值,不可void
Predicate至少1个参数,至多1个参数,返回值固定为bool

三、如何使用委托

3.1 Labmda表达式

TestDelegate d2= (string name) => { 
Console.WriteLine("你好,{0}!", name); 
};

d2("Terry");
3.2匿名方法
delegate void TestDelegate(string myName);
TestDelegate d2 = delegate(string name)
{
     Console.WriteLine("Hello,{0}!", name);
};

d2(“Test”);

3.3 函数申明
 
private void DelegateMethod(string name)
{
     Console.WriteLine("Hello,{0}!", name);
}
TestDelegate d2 = new TestDelegate(DelegateMethod);

d2(“Test”);


四、使用委托有哪些特点

委托类似于 C++ 函数指针,但它们是类型安全的。
委托允许将方法作为参数进行传递。
委托可用于定义回调方法。
委托可以链接在一起;例如,可以对一个事件调用多个方法。
方法不必与委托签名完全匹配。

五、委托使用场景
委托一般都使用在 Observer模式(观察者模式)。

Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。
Observer模式主要包括如下两类对象:
被监视对象:往往包含着其他对象所感兴趣的内容。
监视者:当对象中的某件事发生的时候,会告知建设者,而建设者则会采取相应的行动。

例如:当你程序处理大批量数据时,需要在程序界面显示进度条进行友好提示,这时你通过委托来实现相当方便。

例子:

namespace SignalRTest.Controllers
{
    public class HomeController : Controller
    {
        private TestDelegate.RerutnDelegateMethod onReturnDelegate;// 

        public ActionResult Index(string returnUrl)
        {
            ViewBag.ReturnUrl = returnUrl;

            //委托使用
            onReturnDelegate = new TestDelegate.RerutnDelegateMethod(WriteToLog);
            onReturnDelegate("Hello,My Name Is Delegate!", 18);

            return View();
        }
        /// <summary>
        /// 委托 函数申明
        /// </summary>
        /// <param name="para1"></param>
        /// <param name="age"></param>
        /// <returns></returns>
        public string WriteToLog(string para1, int age)
        {
            string str = string.Empty;
            Console.WriteLine(string.Format("p1:{0},p2:{1}", para1, age)); 
            return str;
        }

        /// <summary>
        /// 方法1:清空委托 
        /// </summary>
        public void ClearDelegate1()
        {
            while (this.onReturnDelegate!=null)
            {
                this.onReturnDelegate -= this.onReturnDelegate;
            } 
        }
        /// <summary>
        /// 方法2:清空委托 
        /// 利用GetInvocationList查询出委托引用,然后进行去除。
        /// </summary>
        public void ClearDelegate2()
        { 
            if (onReturnDelegate!=null)
            {
                System.Delegate[] dels = onReturnDelegate.GetInvocationList();
                for (int i = 0; i < dels.Length;i++ )
                {
                    onReturnDelegate -= dels[i] as TestDelegate.RerutnDelegateMethod;
                }
            }
        }
       

        public ActionResult Chat()
        {

            return View();
        }
    }


    public class TestDelegate
    {
        /// <summary>
        /// 委托 声明
        /// </summary>
        /// <param name="mypara1"></param>
        /// <param name="age"></param>
        /// <returns></returns>
        public delegate string RerutnDelegateMethod(string mypara1, int age);  
    }
}

六、事件

 事件其实没什么不好理解的,声明一个事件不过类似于声明一个进行了封装的委托类型的变量而已。


namespace SignalRTest.Controllers
{
    public class HomeController : Controller
    {
        private TestDelegate.RerutnDelegateMethod onReturnDelegate;// 
 

        public ActionResult Index(string returnUrl)
        {
            ViewBag.ReturnUrl = returnUrl;
 
            //委托使用
            onReturnDelegate = new TestDelegate.RerutnDelegateMethod(WriteToLog);
            onReturnDelegate("Hello,My Name Is Delegate!", 18);



            TestDelegate  td = new TestDelegate();
            td.EventNumberChanged += this.WriteToLog;
            //td.EventNumberChanged += this.WriteToLog;//多个注册无用
            //td.eventNumberChanged += this.WriteToLog;//事件为公用
             
            td.DoSomethings();

            return View();
        }
        /// <summary>
        /// 委托 函数申明
        /// </summary>
        /// <param name="para1"></param>
        /// <param name="age"></param>
        /// <returns></returns>
        public string WriteToLog(string para1, int age)
        {
            string str = string.Empty;
            Console.WriteLine(string.Format("p1:{0},p2:{1}", para1, age)); 
            return str;
        }

        /// <summary>
        /// 方法1:清空委托 
        /// </summary>
        public void ClearDelegate1()
        {
            while (this.onReturnDelegate!=null)
            {
                this.onReturnDelegate -= this.onReturnDelegate;
            } 
        }
        /// <summary>
        /// 方法2:清空委托 
        /// 利用GetInvocationList查询出委托引用,然后进行去除。
        /// </summary>
        public void ClearDelegate2()
        { 
            if (onReturnDelegate!=null)
            {
                System.Delegate[] dels = onReturnDelegate.GetInvocationList();
                for (int i = 0; i < dels.Length;i++ )
                {
                    onReturnDelegate -= dels[i] as TestDelegate.RerutnDelegateMethod;
                }
            }
        }
       

        public ActionResult Chat()
        {

            return View();
        }
    }


    public class TestDelegate
    {
        /// <summary>
        /// 委托 声明
        /// </summary>
        /// <param name="mypara1"></param>
        /// <param name="age"></param>
        /// <returns></returns>
        public delegate string RerutnDelegateMethod(string mypara1, int age);


        /*事件开始*/
        /// <summary>
        /// 声明一个事件
        /// </summary>
        private event RerutnDelegateMethod eventNumberChanged; 
        //public event RerutnDelegateMethod eventNumberChanged; 
         /// <summary>
         /// 对外
         /// 事件访问器的定义 
         /// </summary>
        public event RerutnDelegateMethod EventNumberChanged
        {
            add {
                eventNumberChanged = value;
            }
            remove {
                eventNumberChanged -= value;
            }
        }

        public void DoSomethings()
        {
            if (eventNumberChanged != null)
            {
                string str = eventNumberChanged("This Event DoSomethings!",99);
                Console.WriteLine("return value is {0}", str);
            }
        }
    }
}
七、Observer设计模式:

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

Observer设计模式中主要包括如下两类对象:
Subject:监视对象,它往往包含着其他对象所感兴趣的内容。在本范例中,热水器就是一个监视对象,它包含的其他对象所感兴趣的内容,就是temprature字段,当这个字段的值快到100时,会不断把数据发给监视它的对象。
Observer:监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在本范例中,Observer有警报器和显示器,它们采取的行动分别是发出警报和显示水温。

引出:假设我们有个高档的热水器,我们给它通上电,当水温超过95度的时候:

1、扬声器会开始发出语音,告诉你水的温度;

2、液晶屏也会改变水温的显示,来提示水已经快烧开了。

在本例中,事情发生的顺序应该是这样的:
1、警报器和显示器告诉热水器,它对它的温度比较感兴趣(注册)。
2、热水器知道后保留对警报器和显示器的引用。
3、热水器进行烧水这一动作,当水温超过95度时,通过对警报器和显示器的引用,自动调用警报器的MakeAlert()方法、显示器的ShowMsg()方法。
using System;
using System.Collections.Generic;
using System.Text;

namespace Delegate {
    // 热水器
    public class Heater {
       private int temperature;
       public delegate void BoilHandler(int param);   //声明委托
       public event BoilHandler 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("Alarm:嘀嘀嘀,水已经 {0} 度了:", param);
       }
    }

    // 显示器
    public class Display {
       public static void ShowMsg(int param) { //静态方法
           Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", param);
       }
    }
    
    class Program {
       static void Main() {
           Heater heater = new Heater();
           Alarm alarm = new Alarm();

           heater.BoilEvent += alarm.MakeAlert;    //注册方法
           heater.BoilEvent += (new Alarm()).MakeAlert;   //给匿名对象注册方法
           heater.BoilEvent += Display.ShowMsg;       //注册静态方法

           heater.BoilWater();   //烧水,会自动调用注册过对象的方法
       }
    }
}

输出为:
Alarm:嘀嘀嘀,水已经 96 度了:
Alarm:嘀嘀嘀,水已经 96 度了:
Display:水快烧开了,当前温度:96度。
// 省略...








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值