本文一共分为三个部分:多播委托知识点,多播委托和事件区别,事件应用之管道设计
第一:多播委托的知识点:
A:任何一个委托实例,实际上都是多播委托,即可以+=,也可以-=不过需要注意一点
只有相同对象的相同方法才可以移除,比如相同的静态方法等
B:多播委托,赋值多个方法时,不能异步调用,报错,如果一定需要,可以依次遍历出每个多播委托中的方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DelegateEventDemo
{
public delegate void TestDelegate();
class Program
{
static void Main(string[] args)
{
new Program().Demo();
}
public static void Test() {
Console.WriteLine("我是静态static方法");
}
public void Test2()
{
Console.WriteLine("我是类中普通方法");
}
private void Demo() {
//第一种:lambda
TestDelegate testDelegate = new TestDelegate(() => {
Console.WriteLine("我是lambda");
});
//第二种:静态方法
testDelegate += new TestDelegate(Test);
//第三种:自己类中方法
testDelegate += new TestDelegate(this.Test2);
//第四种:其他类普通方法,
testDelegate += new TestDelegate(new OtherClass().Test2);
//第五种:其他类静态方法
testDelegate += new TestDelegate(OtherClass.Test);
//第一种:lambda,其实是另一个方法,没能取消
testDelegate -= new TestDelegate(() => {
});
//第二种:静态方法,相同的那个方法,能取消
testDelegate -= new TestDelegate(Test);
//第三种:自己类中相同那个静态方法,能取消
testDelegate -= new TestDelegate(this.Test2);
//第四种:其他类普通方法,另一个实例中方法,不能取消
testDelegate -= new TestDelegate(new OtherClass().Test2);
//第五种:其他类静态方法,能取消
testDelegate -= new TestDelegate(OtherClass.Test);
//testDelegate.Invoke();
//testDelegate.BeginInvoke()
//只能移除完全相同的方法,所属对象和方法签名本身
//一个委托实例,包括多个方法,就是多播委托,
//后面两个参数是回调,和参数,
//提示该委托,必须只有一个方法目标,既只能有一个方法
//testDelegate.BeginInvoke(null, null);
foreach (TestDelegate item in testDelegate.GetInvocationList())
{
item.BeginInvoke(null,null);
}
}
}
class OtherClass{
public static void Test()
{
Console.WriteLine("我是其他类静态static方法");
}
public void Test2()
{
Console.WriteLine("我是其他类中普通方法");
}
}
}
第二个知识点:多播委托和事件区别
委托其实是一个类,继承自多播委托的类
它事件,本来就是一个委托的实例,加上event关键字,所以他不是类型,
事件和一般委托实例区别,事件不能在非所属对象中,进行调用,等等,进行一些列安全限制
事件他在外面只能是+=,-=
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EventAndMutityCastDelegate
{
public delegate void HandlerCat();
class Program
{
static void Main(string[] args)
{
//多播委托,就像一个容器,可以放一定标准的方法,(某种签名的方法),
//为什么需要委托呢?凌晨醒来,忽然意识到一个问题,假定如下场景,猫叫引起一系列对象连锁的反应
// 猫叫,
//老鼠跑,狗也叫,小孩哭,父亲咆哮,母亲安抚,哥哥翻身,
new Cat().Miao();
//这里猫叫,触发一系列对象动作,想起委托的作用,就是封装一些列动作,
//这里猫叫,即调用多播委托即可,同时想到事件的原理,正是点击触发,引起连锁反应
///有个严重的问题,依赖多,追求开闭原则,扩展开放,修改关闭,
///不同对象,稍稍修改,换个调用顺序都要修改cat对象,
///
//!!!!!!!!!!!!!!!!就算把事件,多播委托拿进来,仍然是放在miao方法里面,尽量不改动miao方法!!!!!!!!!!!!!!
{
Cat delegatecat = new Cat();
delegatecat.handler += new HandlerCat(new Mouse().Run);
delegatecat.handler += new HandlerCat(new Dog().Scream);
delegatecat.handler += new HandlerCat(new Baby().Cry);
delegatecat.handler.Invoke();
delegatecat.handler = null;
delegatecat.handler += new HandlerCat(new Father().Angry);
delegatecat.handler += new HandlerCat(new Mouther().Love);
delegatecat.handler += new HandlerCat(new Brother().Wrap);
//
delegatecat.MiaoDelegate();
}
{
Cat delegatecat = new Cat();
delegatecat.EventHandlerCat += new HandlerCat(new Mouse().Run);
delegatecat.EventHandlerCat += new HandlerCat(new Dog().Scream);
delegatecat.EventHandlerCat += new HandlerCat(new Baby().Cry);
//参数不同,可以通过lambda封装一下再次调用,非常灵活
delegatecat.EventHandlerCat += () =>
{
new NewMethod().Test(3);
};
//委托其实是一个类,继承自多播委托的类
//事件和一般委托实例区别,事件不能在非所属对象中,进行调用,等等,进行一些列安全限制
//他在外面只能是+=,-=
//delegatecat.EventHandlerCathandler.Invoke();
//delegatecat.EventHandlerCat = null;
delegatecat.EventHandlerCat += new HandlerCat(new Father().Angry);
delegatecat.EventHandlerCat += new HandlerCat(new Mouther().Love);
delegatecat.EventHandlerCat += new HandlerCat(new Brother().Wrap);
//
delegatecat.MiaoEvent();
}
}
}
class NewMethod
{
public void Test(int count)
{
Console.WriteLine("叫三声");
}
}
class Cat {
//灵活运用,没有参数返回,不就是Action委托么?
public HandlerCat handler;
public event HandlerCat EventHandlerCat;
public void Miao() {
Console.WriteLine("我是猫叫");
new Mouse().Run();
new Dog().Scream();
new Baby().Cry();
new Father().Angry();
new Mouther().Love();
new Brother().Wrap();
//..
//万一有,不同参数的方法,怎么办?
new NewMethod().Test(3);
}
//
public void MiaoDelegate() {
Console.WriteLine("我是猫叫");
if (handler!=null)
{
handler.Invoke();
}
//hander.Invoke();
//new Mouse().Run();
//new Dog().Scream();
}
//EentHandlerCat eventhandlerCat 不能把事件当成类型传递
public void MiaoEvent()
{
Console.WriteLine("我是event猫叫");
//它事件,本来就是一个委托的实例,加上event关键字,所以他不是类型,不能也无须再次做如下声明
//调用是这个实例,可以+=,或是-=,相比较多播委托,它限制
//EventHandlerCat eventhandler = new HandlerCat(new Mouse().Run);
//this.EventHandlerCat = new HandlerCat(new Mouse().Run);
//this.EventHandlerCat += new HandlerCat(new Dog().Scream);
//this.EventHandlerCat += new HandlerCat(new Baby().Cry);
hander.Invoke();
hander = null;
//this.EventHandlerCat += new HandlerCat(new Father().Angry);
//this.EventHandlerCat += new HandlerCat(new Mouther().Love);
//this.EventHandlerCat += new HandlerCat(new Brother().Wrap);
//EventHandlerCat.Invoke();
//new Mouse().Run();
//new Dog().Scream();
if (EventHandlerCat!=null)
{
EventHandlerCat.Invoke();
}
}
}
class Mouse {
public void Run() {
Console.WriteLine("Mouse Run");
}
}
class Dog
{
public void Scream()
{
Console.WriteLine("Dog Scream");
}
}
class Baby
{
public void Cry()
{
Console.WriteLine("Baby Cry");
}
}
class Father
{
public void Angry()
{
Console.WriteLine("Father Angry");
}
}
class Mouther
{
public void Love()
{
Console.WriteLine("Mouther Love");
}
}
class Brother
{
public void Wrap()
{
Console.WriteLine("Brother Wrap");
}
}
}
第三个知识点:
事件的应用之管道设计模式,我们程序设计遵循的非常重要的一个模式是,开闭原则,即对修改关闭,对扩展开放,
这里封装固定的逻辑,借助事件可提供一个对外扩展接口, 事件可简单理解是方法的一个容器集合,事实上,整个ASP.NET架构,都是基于这种管道设计模式,处理一个请求,封装固定的cookie,session返回页面html,同时提供很多事件,用来给开发者调用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EventHttpHandler
{
class Program
{
//事件的实际应用,相关设计,管道处理模式
static void Main(string[] args)
{
//事件就是一种特殊的委托实例,可以直接添加方法,进行封装,粗浅地理解为方法容器
//比如吃大排档的过程,分为五步,固定,现在增加一个个性需求,吃饭之前洗脸,或是运动完睡觉等等需求
//传统做法,就是继续添加这些动作,到Eat方法,
//更好的设计,是提示提供一个事件即,方法容器判断不为空执行,从而不改变吃方法,只在外面添加方法到里面去即可
//
PipeDemo pipedemo = new PipeDemo();
pipedemo.MenuBefor += () => {
Console.WriteLine("吃饭之前洗脸");
};
pipedemo.SportAfter += () => {
Console.WriteLine("运动之后睡觉");
};
pipedemo.Eat();
//Action<int> action1
//分析总结,利用事件实现管道模式的好处,方便扩展,
//扩展一下,实际上整个Asp.Net框架,就是基于事件驱动的架构
/*
整个框架中对网页端来的请求HttpHandler,除了生成html,还有很多事情要做,
cookie,session 安全检验,实际上差不多有25个事件,常用的是19个,
框架就是将固定的逻辑封装好,其他额外要处理的事件,通过事件设计成管道模式
提供一个扩展接口,给外面调用
*/
}
}
class PipeDemo {
public event Action MenuBefor;
public event Action DrinkEatingBefor;
public event Action PostEatingBefor;
public event Action ToothBefor;
public event Action SportBefor;
public event Action MenuAfter;
public event Action DrinkEatingAfter;
public event Action PostEatingAfter;
public event Action ToothAfter;
public event Action SportAfter;
public void Eat() {
if (MenuBefor!=null)
{
MenuBefor.Invoke();
}
Console.WriteLine("点餐");
if (MenuAfter != null)
{
MenuAfter.Invoke();
}
Console.WriteLine("上菜");
Console.WriteLine("喝酒吃菜");
Console.WriteLine("剔牙");
if (SportBefor!=null)
{
SportBefor.Invoke();
}
Console.WriteLine("运动");
if (SportAfter!=null)
{
SportAfter.Invoke();
}
}
}
}
参考朝夕教育Eleven老师课堂讲解