一、什么是委托建议打开文章目录进行观看,观看时按照代码示例调试、执行方便理解
1.委托跟方法类似,有参数、有返回值、有修饰符、+delegate。
2.在反编译中,我们所定义的委托在CustomDelegate中都有对应的calss,所以委托的本质:委托类----继承自System.MulticastDelegate的类(MulticastDelegate是一个继承自delegate的特殊的抽象类,自定义类的时候无法主动继承该类,MulticastDelegate类的内部包含有构造函数+方法)
我自己的感受:委托就像是一个自动贩卖机,方法是里面的商品,方法名是商品对应的序号,只要你输入对了序号就能定位到正确的商品。
二、委托的实例化与使用
委托可以通过new来实例化使用,要求必须传递一个和这个委托的参数和返回值完全匹配的方法
在Invoke()时需要根据委托的定义来进行传参
下面例子里使用到的委托类:
////// 1.无参数无返回值委托 /// public delegate void NoReturnNoParameter1(); public class DelegateClass { ////// 2.无参数无返回值委托 /// public delegate void NoReturnNoParameter2(); ////// 3.有参数无返回值委托 /// public delegate void NoReturn(int x, int y); ////// 4.无参数有返回值委托 /// ///public delegate int NoParameter(); /// /// 5.有参数有返回值委托 /// ///public delegate int ReturnAndParameter(out int x, ref int y); /// /// 1.2无参数无返回值的方法 /// public void NoReturnNoParameterMethod() { Console.WriteLine("这是一个无参数无返回值的方法"); } ////// 3.有参数无返回值的方法 /// public void NoReturnMethod(int x, int y) { Console.WriteLine("这是一个有参数无返回值的方法:x={0},y={1}", x, y); } ////// 4.无参数有返回值的方法 /// /// /// public int NoParameterMethod() { Console.WriteLine("这是一个无参数有返回值的方法"); return 1; } ////// 5.有参数有返回值的方法 /// /// /// ///public int ReturnAndParameterMethod(out int x, ref int y) { x = 1; Console.WriteLine("这是一个有参数有返回值的方法:x={0},y={1}", x, y); return y; } }
在上面的委托类中增加一个示例方法Show():
////// 委托实例化使用示例 /// 上面的代码中,我们定义了一个委托类型的变量,并且将一个方法作为委托的实例化, /// 委托的有无参数、返回值,要与方法的有无参数、返回值保持一致。 /// public void Show() { //===================================多种实例化================================================== //第一种方法(委托实例化后传入返回值、参数完全相同的方法的方法名) NoReturnNoParameter1 delegate1 = new NoReturnNoParameter1(NoReturnNoParameterMethod); NoReturnNoParameter2 delegate2 = new NoReturnNoParameter2(NoReturnNoParameterMethod); NoReturn delegate3 = new NoReturn(NoReturnMethod); NoParameter delegate4 = new NoParameter(NoParameterMethod); ReturnAndParameter deletegate5 = new ReturnAndParameter(ReturnAndParameterMethod); //第二种方法(直接指向返回值、参数完全相同的方法)----编译器提供的语法糖 NoReturnNoParameter1 delegate11 = NoReturnNoParameterMethod; NoReturnNoParameter2 delegate22 = NoReturnNoParameterMethod; NoReturn delegate33 = NoReturnMethod; NoParameter delegate44 = NoParameterMethod; ReturnAndParameter deletegate55 = ReturnAndParameterMethod; //第三种方式(直接指向Lambda表达式) NoReturnNoParameter1 delegate111 = () => { }; NoReturnNoParameter2 delegate222 = () => { }; NoReturn delegate333 = ( x, y ) => { }; NoParameter delegate444 = () => 1; ReturnAndParameter deletegate555 = (out int x, ref int y) => { x = 1; y = 2; return y; }; //===================================执行委托的三个方法======================================= delegate1.Invoke(); delegate2.Invoke(); delegate3.Invoke(1, 2); int num1 = delegate4.Invoke(); int y = 2; int num2= deletegate5.Invoke(out num2, ref y); //开启线程执行委托 //delegate1.BeginInvoke(null, null); //回调 //delegate1.EndInvoke(null); }
调用方法测试:
static void Main(string[] args)
{
DelegateClass delegateClass = new DelegateClass();
delegateClass.Show();
}
执行结果:
委托的优势:
1.代码更稳定,中控方法不需要修改
2.多个情况需要的执行逻辑不在同一个方法中,减少了局部改动测试整体的需要。–逻辑解耦
3.从上而下减少了重复代码,公共逻辑宠用
使用委托的场景建议:
1.方法内部业务逻辑耦合严重
2.如果多个方法,有很多重复代码—去掉重复代码–逻辑重用
需求场景:需要满足多条件多方案并且后续会有公共业务逻辑增加
比如:中国人讲中文,美国人讲英语,日本人讲日语
后期需求:
增加公共逻辑:说话前要举手
正常做法会是:
1.在同一个方法中根据传递进来的标识符进行判断
----缺点:如果变更需求就需要更改原方法,可能会导致整个方法进行重新测试。
----优点:增加公共逻辑方便
2.写多个方法,然后按需调用
----优点:相比第一个方法,只需要新增一个独立的方法,对其他的功能不会造成影响
----缺点:如果需要增加公共逻辑需要每个方法都进行重复代码的新增
上面两个方法优缺点都很明显,委托可以完美的将上面两个方案的优点结合避免缺点出现(既没有大量重复代码,也相对稳定),便于后期维护。
代码:
public class PeopleClass
{
///
/// 姓名
///
public string Name { get; set; }
///
/// 国家
///
public string Country { get; set; }
///
/// 中国的人语言
///
public void Chinese()
{
Console.WriteLine("说中文");
}
///
/// 美国人的语言
///
public void Americans()
{
Console.WriteLine("Say English");
}
///
/// 日本人的语言
///
public void Japanese()
{
Console.WriteLine("は日本語を話す");
}
//=====================================================这是增加公共逻辑前后的分割线======================================================================
///
/// 定义一个委托
///
public delegate void PeopleLanguage();
///
/// 声明一个传递委托的方法,方便共用新增的通用逻辑
///
///
public void PeopleMethod(PeopleLanguage language)
{
//新增的公共逻辑:说话前要举手
Console.WriteLine("举手!");
language.Invoke();
}
}
调用方法:
static void Main(string[] args)
{
PeopleClass peopleClass = new PeopleClass();
//中国人说话
PeopleLanguage peopleLanguage = new PeopleLanguage(peopleClass.Chinese);
peopleClass.PeopleMethod(peopleLanguage);
//美国人说话
PeopleLanguage peopleLanguage2 = new PeopleLanguage(peopleClass.Americans);
peopleClass.PeopleMethod(peopleLanguage2);
//日本人说话
PeopleLanguage peopleLanguage3 = new PeopleLanguage(peopleClass.Japanese);
peopleClass.PeopleMethod(peopleLanguage3);
}
结果:
把委托这个箱子,一层一层的包包装,在每一次执行的时候,增加一些业务逻辑.要执行的核心业务逻辑是在最内部的这个箱子中,执行顺序是从最外层执行到最内层一层一层的执行出来。
引用场景:AOP;装饰器
委托嵌套Demo(1)----简易版:
示意图:
public class DelegateNestedClass
{
//第一步 声明一个委托
public delegate void MyNameIsDelegate();
public static void ThisIsClass()
{
//第二步 实例化类
MyNameIsClass myNameIsClass = new MyNameIsClass();
//第三步 通过反射获取类中的方法
Type type = myNameIsClass.GetType();
MethodInfo methodInfo = type.GetMethod("MyNameIsMethod");
//第四步 实例化委托→委托中存在行为→行为执行方法
MyNameIsDelegate myNameIsDelegate = new MyNameIsDelegate(() => {
methodInfo.Invoke(myNameIsClass, null);
});
//第五步 套娃开始
//1.第一层套娃
MyNameIsDelegate myNameIsDelegate1 = new MyNameIsDelegate(() => {
myNameIsDelegate.Invoke();
});
//2.第二层套娃
MyNameIsDelegate myNameIsDelegate2 = new MyNameIsDelegate(() => {
myNameIsDelegate1.Invoke();
});
//第六步 执行委托
myNameIsDelegate2.Invoke();
}
}
///
/// 我是一个类
///
public class MyNameIsClass
{
///
/// 我是一个方法
///
public void MyNameIsMethod()
{
Console.WriteLine("我是一个方法");
}
}
委托嵌套Demo(2)----进阶版(特性):
可以自由的在执行Method方法的前后增加业务逻辑,如下图所示:
public delegate void MyNameIsDelegate();
public static void ThisIsClass()
{
MyNameIsClass myNameIsClass = new MyNameIsClass();
Type type = myNameIsClass.GetType();
MethodInfo methodInfo = type.GetMethod("MyNameIsMethod");
MyNameIsDelegate myDelegate= new MyNameIsDelegate(() =>
{
methodInfo.Invoke(myNameIsClass, null);
});
if (methodInfo.IsDefined(typeof(MethodAttribute), true))
{
foreach (MethodAttribute methodAttribute in methodInfo.GetCustomAttributes())
{
myDelegate = methodAttribute.Do(myDelegate);
}
}
myDelegate.Invoke();
}
public abstract class MethodAttribute: Attribute
{
public abstract MyNameIsDelegate Do(MyNameIsDelegate myNameIsDelegate);
}
///
/// 定义一个特性,特性中存在一个以委托为方法
///
public class LogAttribute : MethodAttribute
{
public override MyNameIsDelegate Do(MyNameIsDelegate myNameIsDelegate)
{
MyNameIsDelegate myDelegate=new MyNameIsDelegate(()=>{
Console.WriteLine("LogAttribute在执行委托之前输出了一条日志");
myNameIsDelegate.Invoke();
Console.WriteLine("LogAttribute在执行委托之后输出了一条日志");
});
return myDelegate;
}
}
///
/// 又定义一个特性,特性中存在一个以委托为方法
///
public class LogAgainAttribute : MethodAttribute
{
public override MyNameIsDelegate Do(MyNameIsDelegate myNameIsDelegate)
{
MyNameIsDelegate myDelegate = new MyNameIsDelegate(() => {
Console.WriteLine("LogAgainAttribute在执行委托之前输出了一条日志");
myNameIsDelegate.Invoke();
Console.WriteLine("LogAgainAttribute在执行委托之后输出了一条日志");
});
return myDelegate;
}
}
使用到的类:
////// 我是一个类 /// public class MyNameIsClass { ////// 我是一个方法 /// [Log] [LogAgain] public void MyNameIsMethod() { Console.WriteLine("我是一个方法"); } }
执行结果:
Action:来自于System.RunTime的一个声明好无返回值(可带有参数)的delegate
Func来自于System.RunTime的一个声明好有返回值(可带有参数)的delegate
----尖括号中前面类型参数:输入参数(最多支持16个),最后面的类型参数是作为返回值
Action和Func存在的意义:
委托的本质就是类,定义多个委托,其实就是新增了多个类。使用Action/Func便不需要我们每次都去新增委托,可以把委托做到统一。
////// 1.无参数无返回值的方法 /// public void NoReturnNoParameterMethod() { Console.WriteLine("这是一个无参数无返回值的方法"); } ////// 2.有参数无返回值的方法 /// public void NoReturnMethod(int x, int y) { Console.WriteLine("这是一个有参数无返回值的方法:x={0},y={1}", x, y); } ////// 3.无参数有返回值的方法 /// /// /// public int NoParameterMethod() { Console.WriteLine("这是一个无参数有返回值的方法"); return 1; } ////// 4.有参数有返回值的方法 /// /// /// ///public int ReturnAndParameterMethod(int x, string y) { Console.WriteLine("这是一个有参数有返回值的方法:x={0},y={1}", x, y); return x; } public void show() { //无返回值无参数Action示例 Action action = new Action(NoReturnNoParameterMethod); action.Invoke(); //无返回值有参数Action示例 Action action2 = new Action (NoReturnMethod); action2.Invoke(1, 2); //有返回值无参数Action示例 Func func = new Func (NoParameterMethod); func.Invoke(); //有返回值有参数Action示例 Func func2 = new Func (ReturnAndParameterMethod); func2.Invoke(4, "Hello Word"); }
打破最多入参16个的限制(虽然应该是用不到的):
public class FrameWorkDelegate
{
public delegate void Action(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17,T18 arg18);
public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18);
public void show()
{
//传入18个参数
Action action = null;
//传入18个参数
Func func = null;
}
}
六、多播委托
1.增加方法(+=)可以通过+= 把多个方法添加到这个委托中去,执行委托的时候,按照添加方法的顺序依次去执行委托。
可以通过-=移除方法—是从后往前,逐个匹配,如果匹配不到,就不做任何操作就不做任何操作;如果匹配到,就把当前这个移除,且停止去继续往后匹配。
----实例中的方法无法移除,比如示例中的:new Student().NoReturnNoParameterMethodThree,因为此处相当于每次都声明一个新的实例,所以此处与上面的并不是同一个实例导致移除无效。
----lambda表达式也无法移除,因为lambada表达式是在底层会生成一个方法。
额外用到的类:
public class Student
{
public void NoReturnNoParameterMethodThree()
{
Console.WriteLine("第三个执行的方法");
}
public static void NoReturnNoParameterMethodFour()
{
Console.WriteLine("第四个执行的方法");
}
public void NoReturnMethodThree(int x, string y)
{
Console.WriteLine($"第三个执行的方法:x={x},y={y}");
}
public static void NoReturnMethodFour(int x, string y)
{
Console.WriteLine($"第四个执行的方法:x={x},y={y}");
}
public int NoParameterMethodThree()
{
Console.WriteLine("第三个执行的方法");
return 1;
}
public static int NoParameterMethodFour()
{
Console.WriteLine("第四个执行的方法");
return 1;
}
public int ReturnAndParameterMethodThree(int x, string y)
{
Console.WriteLine("第三个执行的有参数有返回值的方法:x={0},y={1}", x, y);
return x;
}
public static int ReturnAndParameterMethodFour(int x, string y)
{
Console.WriteLine("第四个执行的有参数有返回值的方法:x={0},y={1}", x, y);
return x;
}
}
示例类:
public class FrameWorkDelegate
{
///
/// 1.无参数无返回值的方法
///
public void NoReturnNoParameterMethod()
{
Console.WriteLine("第一、五次执行的无参数无返回值的方法");
}
public void NoReturnNoParameterMethod2()
{
Console.WriteLine("第二次执行的无参数无返回值的方法");
}
///
/// 2.有参数无返回值的方法
///
public void NoReturnMethod(int x, string y)
{
Console.WriteLine($"第一、五次执行的参数无返回值的方法:x={x},y={y}");
}
public void NoReturnMethod2(int x, string y)
{
Console.WriteLine($"第二次执行的有参数无返回值的方法:x={x},y={y}");
}
///
/// 3.无参数有返回值的方法
///
///
///
public int NoParameterMethod()
{
Console.WriteLine("第一、五次执行的无参数有返回值的方法");
return 1;
}
public int NoParameterMethod2()
{
Console.WriteLine("第二次执行的无参数有返回值的方法");
return 1;
}
///
/// 4.有参数有返回值的方法
///
///
///
///
public int ReturnAndParameterMethod(int x, string y)
{
Console.WriteLine("第一、五次执行的有参数有返回值的方法:x={0},y={1}", x, y);
return x;
}
public int ReturnAndParameterMethod2(int x, string y)
{
Console.WriteLine("第二次执行的有参数有返回值的方法:x={0},y={1}", x, y);
return x;
}
public void show()
{
Console.WriteLine("============无参无返回值示例============");
Action action1 = new Action(NoReturnNoParameterMethod);
action1 += NoReturnNoParameterMethod2;
//Student类中的一个无参无返回值的方法
action1 += new Student().NoReturnNoParameterMethodThree;
//Student类中的一个无参无返回值的静态方法
action1 += Student.NoReturnNoParameterMethodFour;
//可重复添加同一个方法
action1 += NoReturnNoParameterMethod;
action1 += () =>
{
Console.WriteLine("这是lambda表达式");
};
action1.Invoke();
//多播委托开启线程执行
foreach (Action action in action1.GetInvocationList())
{
//不知道是不是.net版本升级的问题,BeginInvoke使用一直报错,但是一直到不到报错原因,只能换位Task.Run()
//action.BeginInvoke(null, null);
Task.Run(() => action.Invoke());
}
Console.WriteLine("============有参无返回值示例============");
Action action2 = new Action(NoReturnMethod);
action2 += NoReturnMethod2;
action2 += new Student().NoReturnMethodThree;
action2 += Student.NoReturnMethodFour;
action2 += NoReturnMethod;
action2 += (x, y) =>
{
Console.WriteLine($"这是lambda表达式{x},{y}");
};
action2.Invoke(1, "2");
//多播委托开启线程执行
foreach (Action action in action2.GetInvocationList())
{
//action.BeginInvoke(1,"2",null, null);
Task.Run(() => action.Invoke(1, "2"));
}
Console.WriteLine("============无参有返回值示例============");
Func func1 = new Func(NoParameterMethod);
func1 += NoParameterMethod2;
func1 += new Student().NoParameterMethodThree;
func1 += Student.NoParameterMethodFour;
func1 += NoParameterMethod;
func1 += () =>
{
Console.WriteLine("这是lambda表达式");
return 1;
};
func1.Invoke();
//多播委托开启线程执行
foreach (Func func in func1.GetInvocationList())
{
//func.BeginInvoke(null, null);
Task.Run(() => func.Invoke());
}
Console.WriteLine("============有参有返回值示例============");
Func func2 = new Func(ReturnAndParameterMethod);
func2 += ReturnAndParameterMethod2;
func2 += new Student().ReturnAndParameterMethodThree;
func2 += Student.ReturnAndParameterMethodFour;
func2 += ReturnAndParameterMethod;
func2 += (x, y) =>
{
Console.WriteLine($"这是lambda表达式{x},{y}");
return 1;
};
func2.Invoke(3, "4");
foreach (Func func in func2.GetInvocationList())
{
//func.BeginInvoke(3,"4",null,null);
Task.Run(() => func.Invoke(3,"4"));
}
}
}
调用:
static void Main(string[] args)
{
FrameWorkDelegate frameWorkDelegate = new FrameWorkDelegate();
frameWorkDelegate.show();
}
执行结果:
示例:
public void show()
{
Console.WriteLine("============无参无返回值示例============");
Action action1 = new Action(NoReturnNoParameterMethod);
action1 += NoReturnNoParameterMethod2;
//Student类中的一个无参无返回值的方法
action1 += new Student().NoReturnNoParameterMethodThree;
//Student类中的一个无参无返回值的静态方法
action1 += Student.NoReturnNoParameterMethodFour;
//可重复添加同一个方法
action1 += NoReturnNoParameterMethod;
action1 += () =>
{
Console.WriteLine("这是lambda表达式");
};
//移除方法
action1 -= NoReturnNoParameterMethod;
action1 -= NoReturnNoParameterMethod2;
//此处移除无效,因为new Student()相当于每次都声明一个新的实例,所以此处与上面的并不是同一个实例导致移除无效。lambda表达式也无法移除,因为lambada表达式是在底层会生成一个方法。
action1 -= new Student().NoReturnNoParameterMethodThree;
action1 -= Student.NoReturnNoParameterMethodFour;
action1.Invoke();
}
结果:
七、事件和委托
示例背景:猫叫了→老鼠跑了→狗叫了→小孩哭了(猫叫了一声引发了一系列反应)
解决方案:
----依赖太重、职责不单一
public class Cat
{
///
/// 猫叫了
///
public void Meow()
{
Console.WriteLine("猫叫了");
#region 普通的方法
new Mouse().Run();
new Dog().Bark();
new Baby().Cry();
#endregion
}
}
public class Mouse
{
///
/// 老鼠跑了
///
public void Run()
{
Console.WriteLine("老鼠跑了");
}
}
public class Dog
{
///
/// 狗叫了
///
public void Bark()
{
Console.WriteLine("狗叫了");
}
}
public class Baby
{
///
/// 小孩哭了
///
public void Cry()
{
Console.WriteLine("小孩哭了");
}
}
2.观察者模式(将不属于我的东西转移出去)
①.多播委托----从语法层面支持
a.多播委托此处有两个几乎一模一样的例子:
例子a是委托
例子b是事件
关系:事件是委托的实例(实例是特殊的委托)。
区别:事件比委托更安全
①.事件只能在所在类的内部执行(比如:子类无法使用父类中的事件,但是可以使用父类中的委托。实现类中无法调用目标类中的事件,但是可以调用目标类中的委托)
②.委托可以直接赋值null进行清空,事件不可以。
事件应用场景:当需求固定要在某一个动作之后再按照顺序执行一些方法的时候,使用事件防止别人跳过动作调执行方法。
----将所有的方法通过多播委托+=到action中,使每个方法的职责单一,保证了所有方法的稳定性
使用到的类:
public class Cat
{
///
/// 猫叫了
///
public void Meow()
{
Console.WriteLine("猫叫了");
}
#region 多播委托用到的
public Action catAction = null;
public void CatActionMethod()
{
Console.WriteLine("开始蝴蝶效应了");
if (catAction!=null)
{
catAction.Invoke();
}
}
#endregion
}
public class Mouse
{
///
/// 老鼠跑了
///
public void Run()
{
Console.WriteLine("老鼠跑了");
}
}
public class Dog
{
///
/// 狗叫了
///
public void Bark()
{
Console.WriteLine("狗叫了");
}
}
public class Baby
{
///
/// 小孩哭了
///
public void Cry()
{
Console.WriteLine("小孩哭了");
}
}
使用多播委托进行调用:
static void Main(string[] args)
{
Cat cat = new Cat();
#region 多播委托
cat.catAction += cat.Meow;
cat.catAction += new Mouse().Run;
cat.catAction += new Dog().Bark;
cat.catAction += new Baby().Cry;
cat.CatActionMethod();
#endregion
}
执行结果:
事件观察者模式的三大要素:1.发布者 2.订阅者 3.订阅。多在winform中的控件事件绑定使用,ASP.NET MV5的管道处理模型就是通过十九大事件完成的。
基于a的实例增加一个Event关键字
用到的类:
public class Cat
{
///
/// 猫叫了
///
public void Meow()
{
Console.WriteLine("猫叫了");
}
#region 事件用到的
public event Action catEventAction = null;
public void CatEventActionMethod()
{
if (catEventAction != null)
{
Console.WriteLine("开始蝴蝶效应了");
catEventAction.Invoke();
}
}
#endregion
}
public class Mouse
{
///
/// 老鼠跑了
///
public void Run()
{
Console.WriteLine("老鼠跑了");
}
}
public class Dog
{
///
/// 狗叫了
///
public void Bark()
{
Console.WriteLine("狗叫了");
}
}
public class Baby
{
///
/// 小孩哭了
///
public void Cry()
{
Console.WriteLine("小孩哭了");
}
}
调用:
static void Main(string[] args)
{
Cat cat = new Cat();
#region 事件
cat.catEventAction += cat.Meow;
cat.catEventAction += new Mouse().Run;
cat.catEventAction += new Dog().Bark;
cat.catEventAction += new Baby().Cry;
cat.CatEventActionMethod();
#endregion
}
执行结果:
----定义一个接口,所有的类都继承这个接口并实现里面的共通方法,最后在执行方法中循环并调用
使用到的类:
////// 定义一个通用接口(第二种观察者模式) /// public interface IObject { void DoAction(); } public class Cat : IObject { ////// 猫叫了 /// public void Meow() { Console.WriteLine("猫叫了"); } #region 第二种观察者模式 public Listobserverlist = new List (); public void CatObserver() { Console.WriteLine("开始蝴蝶效应了"); if (observerlist.Count > 0) { foreach (var item in observerlist) { item.DoAction(); } } } public void DoAction() { this.Meow(); } #endregion } public class Mouse : IObject { public void DoAction() { this.Run(); } /// /// 老鼠跑了 /// public void Run() { Console.WriteLine("老鼠跑了"); } } public class Dog : IObject { ////// 狗叫了 /// public void Bark() { Console.WriteLine("狗叫了"); } public void DoAction() { this.Bark(); } } public class Baby : IObject { ////// 小孩哭了 /// public void Cry() { Console.WriteLine("小孩哭了"); } public void DoAction() { this.Cry(); } }
调用:
static void Main(string[] args)
{
Cat cat = new Cat();
#region 第二种观察者模式
cat.observerlist.Add(new Cat());
cat.observerlist.Add(new Mouse());
cat.observerlist.Add(new Dog());
cat.observerlist.Add(new Baby());
cat.CatObserver();
#endregion
}
执行结果:
观察者三大要素:发布者,订阅者,订阅
PublicNumber类为发布者,Friends类和Others类为订阅者,Subscribe方法为订阅 示例的关系为
订阅者订阅公众号(Subscribe方法),公众号发布一篇文章(发布者动作),订阅者去浏览文章,并关注作者(订阅者动作)。
使用到的Demo类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyDelegateProject
{
///
/// 第一步创建一个类
/// 关注我的公众号
///
public class EventDelegateDemo
{
///
/// 发布者的实例
///
private static PublicNumber publicNumber = new PublicNumber()
{
Id = 1,
//公众号名字
Name = "小张的琐碎日记"
};
///
/// 订阅:关联发布者和订阅者之间的关系(初始化他们的关系)
///
public static void Subscribe()
{
#region 建立发布者和订阅者之间的关系
//订阅者的实例
Friends friends = new Friends()
{
Id = 1,
Name = "美女"
};
//订阅者的实例
Others others = new Others()
{
Id = 1,
Name = "路人"
};
//建立发布者和订阅者之间的关系
publicNumber.Push += friends.Read;
publicNumber.Push += others.ReadAndAddFriends;
#endregion
}
public static void Publish()
{
//公众号中发布一篇文章
publicNumber.PublishArticles();
}
}
///
/// 公众号类
/// 发布者:对外发布事件,当触发一个动作后触发事件
///
public class PublicNumber
{
///
/// 公众号的ID
///
public int Id { get; set; }
///
/// 公众号的名称
///
public string Name { get; set; }
///
/// 发布者的动作,发布文章
///
public void PublishArticles()
{
MessageInfo messageInfo = new MessageInfo()
{
Id=1,
Title= "关于事件观察者这件事",
Description="这是这篇文章的内容",
VXCode="ThisisVXCode"
};
Console.WriteLine($"发布一篇标题为《{messageInfo.Title}》的文章");
Push.Invoke(this,messageInfo);
}
///
///
///
public event EventHandler Push;
}
///
/// 关注公众号的人(朋友)
/// 事件观察者模式的三大要素:订阅者:对发布的事情表示关注
///
public class Friends
{
public int Id { get; set; }
///
/// 朋友的名字
///
public string Name { get; set; }
///
/// 浏览公众号信息的动作
///
public void Read(object? sender, EventArgs e)
{
MessageInfo mi=(MessageInfo)e ;
Console.WriteLine($"朋友们观看了:Title:{mi.Title},Description:{mi.Description}");
}
}
///
/// 关注公众号的人(其他人)
/// 事件观察者模式的三大要素:订阅者:对发布的事情表示关注
///
public class Others
{
public int Id { get; set; }
///
/// 老师的名字
///
public string Name { get; set; }
///
/// 增加新人动作
///
public void ReadAndAddFriends(object? sender, EventArgs e)
{
MessageInfo mi = (MessageInfo)e;
Console.WriteLine($"陌生人观看了:Title:{mi.Title},Description:{mi.Description},并加作者微信:{mi.VXCode}");
}
}
///
/// 公众号推送的内容
///
public class MessageInfo : EventArgs
{
public int Id { get; set; }
///
/// 标题
///
public string Title { get; set; }
///
/// 内容
///
public string Description{get;set;}
///
/// 作者微信号
///
public string VXCode { get; set; }
}
}
调用方法:
static void Main(string[] args)
{
//第一步 初始化发布者和订阅者之间的关系
EventDelegateDemo.Subscribe();
//第二步 执行事件
EventDelegateDemo.Publish();
}



