C# 委托、lambda表达式和事件 (7) 持续更新
引用方法
在C++,函数指针只不过是一个指向内存位置的指针,它不是类型安全的。
C# 委托 定义了返回类型和参数的类型。委托类包含对方法的引用,还可以包含多个方法引用。
定义委托
public delegate double TwoLongsOp(long first, long second); public delegate string GetAString();
委托派生自 System.MulticastDelegate,而 System.MulticastDelegate 又派生自 System.Delegate。
public delegate string GetAString(); static void Main(string[] args)
{
int x = ;
Console.WriteLine(x.ToString()); GetAString stringFun = new GetAString(x.ToString);
Console.WriteLine(stringFun());
} // 以下两种方法一样
stringFun();
stringFun.Invoke();
GetAString stringFun = new GetAString(x.ToString);
GetAString stringFun2 = x.ToString;
委托它们类型是安全的,可以确保被调用的方法的签名是正确的。但它们不关心什么类型的对象上调用该方法,甚至不考虑该方法是静态方法,还是实例方法。
class MyClass
{
public static string getStr()
{
return "Hello";
}
} static void Main(string[] args)
{
GetAString stringFun = MyClass.getStr;
Console.WriteLine(stringFun());
}
委托数组
GetAString[] stringFun = { MyClass.getStr };
Console.WriteLine(stringFun[]());
泛型 Action<T> 委托表示引用一个 void 返回类型的方法。Action 可以调用 0 ~ 16 个参数的方法。
Func<T> 引用 带 返回类型的方法,Func可以调用 0 ~ 16 个参数的方法。
class MyClass
{
public static string getString(string s)
{
return "Hello "+ s;
} public static void Call()
{
Console.WriteLine("Hello Call");
} } static void Main(string[] args)
{
Func<string, string> stringFun = MyClass.getString;
Console.WriteLine(stringFun("Wo"));
Action fun2 = MyClass.Call;
fun2();
}
多播委托
存储两个方法的引用
增加 += 删除 -=
class MyClass
{
public static void Hello(string s)
{
Console.WriteLine("Hello " + s);
} public static void Call(string s)
{
Console.WriteLine("Call " + s);
} } static void Main(string[] args)
{
Action<string> action = MyClass.Hello;
action += MyClass.Call; action("Zhao"); action -= MyClass.Call; action("Zhao2");
}
如果 Hello 方法报错了,第二个 Call 就不会执行了。可以用以下代替。
Action<string> action = MyClass.Hello;
action += MyClass.Call; Delegate[] delegates = action.GetInvocationList();
foreach (Action<string> action2 in delegates)
{
try
{
action2("Python");
}
catch (Exception)
{
}
}
匿名方法
Action<string> action = delegate(string str)
{
Console.WriteLine("Anonymous " + str);
}; Delegate[] delegates = action.GetInvocationList();
foreach (Action<string> action2 in delegates)
{
try
{
action2("Python");
}
catch (Exception)
{
}
}
匿名方法不能使用跳转语句(break、goto 或 continue)跳到该匿名方法的外部。匿名方法内部能访问不安全的代码。也不能使用 ref 和 out 参数。但可以使用匿名方法外部定义的其他变量。
lmadba
Action<string> action = str => Console.WriteLine("lambda " + str);
Action<string> action2 = (str) => { Console.WriteLine("lambda " + str); };
匿名方法
int sum = ;
Func<int, int> fun = x => x + sum;
Console.WriteLine(fun() + " " + sum);
事件
class Program
{
public class CustomEventArgs : EventArgs
{
public CustomEventArgs(string car)
{
this.Car = car;
} public string Car { get; private set; }
} public static event EventHandler<CustomEventArgs> NewEvent; static void Main(string[] args)
{
NewEvent += NewEventHandler;
NewEvent += NewEventHandler;
NewEvent -= NewEventHandler;
CustomEventArgs eventArgs = new CustomEventArgs("Audio");
NewEvent(null, eventArgs);
} static void NewEventHandler(object sender, CustomEventArgs e)
{
Console.WriteLine("事件处理参数 " + e.Car);
}
}
NewEvent += NewEventHandler; // 添加事件
NewEvent -= NewEventHandler; // 移除事件
弱事件
在不需要使用事件时,需要移除事件。否则的话,会出现内存泄露。另一种方法用弱事件。
public class WeakCarInfoEventManager : WeakEventManager
{
public static void AddListener(object source, IWeakEventListener listener)
{
CurrentManager.ProtectedAddListener(source, listener);
} public static void RemoveListener(object source, IWeakEventListener listener)
{
CurrentManager.ProtectedRemoveListener(source, listener);
} public static WeakCarInfoEventManager CurrentManager
{
get
{
WeakCarInfoEventManager manager = GetCurrentManager(typeof(WeakCarInfoEventManager)) as WeakCarInfoEventManager;
if (manager == null)
{
manager = new WeakCarInfoEventManager();
SetCurrentManager(typeof(WeakCarInfoEventManager), manager);
}
return manager;
}
} protected override void StartListening(object source)
{
(source as CarDealer).NewCarInfo += CarDealer_NewCarInfo;
} void CarDealer_NewCarInfo(object sender, CarInfoEventArgs e)
{
DeliverEvent(sender, e);
}
protected override void StopListening(object source)
{
(source as CarDealer).NewCarInfo -= CarDealer_NewCarInfo;
}
}
侦听
var dealer = new CarDealer(); var michael = new Consumer("Michael");
WeakCarInfoEventManager.AddListener(dealer, michael); dealer.NewCar("Mercedes"); var sebastian = new Consumer("Sebastian");
WeakCarInfoEventManager.AddListener(dealer, sebastian); dealer.NewCar("Ferrari"); WeakCarInfoEventManager.RemoveListener(dealer, michael); dealer.NewCar("Red Bull Racing");
还可以用内置的 泛型弱事件 写的代码更少
var dealer = new CarDealer(); var michael = new Consumer("Michael");
WeakEventManager<CarDealer, CarInfoEventArgs>.AddHandler(dealer, "NewCarInfo", michael.NewCarIsHere); dealer.NewCar("Mercedes"); var sebastian = new Consumer("Sebastian");
WeakEventManager<CarDealer, CarInfoEventArgs>.AddHandler(dealer, "NewCarInfo", sebastian.NewCarIsHere); dealer.NewCar("Ferrari"); WeakEventManager<CarDealer, CarInfoEventArgs>.RemoveHandler(dealer, "NewCarInfo", michael.NewCarIsHere); dealer.NewCar("Red Bull Racing");
C# 委托、lambda表达式和事件 (7) 持续更新的更多相关文章
- C#编程 委托 Lambda表达式和事件
委托 如果我们要把方法当做参数来传递的话,就要用到委托.简单来说委托是一个类型,这个类型可以赋值一个方法的引用. 声明委托 在C#中使用一个类分两个阶段,首选定义这个类,告诉编译器这个类由什么字段和方 ...
- C#学习笔记三(委托·lambda表达式和事件,字符串和正则表达式,集合,特殊的集合)
委托和事件的区别 序号 区别 委托 事件 1 是否可以使用=来赋值 是 否 2 是否可以在类外部进行调用 是 否 3 是否是一个类型 是 否,事件修饰的是一个对象 public delegate vo ...
- 委托、Lambda表达式、事件系列07,使用EventHandler委托
谈到事件注册,EventHandler是最常用的. EventHandler是一个委托,接收2个形参.sender是指事件的发起者,e代表事件参数. □ 使用EventHandler实现猜拳游戏 使用 ...
- 委托、Lambda表达式、事件系列06,使用Action实现观察者模式,体验委托和事件的区别
在"实现观察者模式(Observer Pattern)的2种方式"中,曾经通过接口的方式.委托与事件的方式实现过观察者模式.本篇体验使用Action实现此模式,并从中体验委托与事件 ...
- 委托、Lambda表达式、事件系列05,Action委托与闭包
来看使用Action委托的一个实例: static void Main(string[] args) { int i = 0; Action a = () => i++; a(); a(); C ...
- 委托、Lambda表达式、事件系列04,委托链是怎样形成的, 多播委托, 调用委托链方法,委托链异常处理
委托是多播委托,我们可以通过"+="把多个方法赋给委托变量,这样就形成了一个委托链.本篇的话题包括:委托链是怎样形成的,如何调用委托链方法,以及委托链异常处理. □ 调用返回类型为 ...
- 委托、Lambda表达式、事件系列03,从委托到Lamda表达式
在"委托.Lambda表达式.事件系列02,什么时候该用委托"一文中,使用委托让代码简洁了不少. namespace ConsoleApplication2 { internal ...
- 委托、Lambda表达式、事件系列02,什么时候该用委托
假设要找出整型集合中小于5的数. static void Main(string[] args) { IEnumerable<int> source = new List<int&g ...
- 委托、Lambda表达式、事件系列01,委托是什么,委托的基本用法,委托的Method和Target属性
委托是一个类. namespace ConsoleApplication1 { internal delegate void MyDelegate(int val); class Program { ...
- C#高级编程(第9版) 第08章 委托、lambda表达式和事件 笔记
本章代码分为以下几个主要的示例文件: 1. 简单委托 2. 冒泡排序 3. lambda表达式 4. 事件示例 5. 弱事件 引用方法 委托是寻址方法的.NET版本.在C++中函数 ...
随机推荐
- idea配置git的步骤
第一次git到GitHub过程 打开到项目 这样就不用再用git Bash敲命令了
- Java反射:Web学习的灵魂
反射:Web学习的灵魂 我们从最初的 javac -HelloWorld.java,到面向对象部分,我们可以将Java代码在计算机中经历的阶段分为三部分:Scource源代码阶段 -- Class类对 ...
- webpack-dev-server 导致的 invalid host header
这几天做的一个项目,在这个项目的 js 方面,我将其分业务和功能的拆分成模块化,然后使用 webpack 来进行打包.(第一次在公司产品中使用 webpack) 然后使用了 webpack-dev-s ...
- 聊聊BIO、NIO与AIO的区别
题目:说一下BIO/AIO/NIO 有什么区别?及异步模式的用途和意义? 1F 说一说I/O首先来说一下什么是I/O? 在计算机系统中I/O就是输入(Input)和输出(Output)的意思,针对不同 ...
- Java实现无向图的建立与遍历
一.基于邻接矩阵表示法的无向图 邻接矩阵是一种利用一维数组记录点集信息.二维数组记录边集信息来表示图的表示法,因此我们可以将图抽象成一个类,点集信息和边集信息抽象成类的属性,就可以在Java中描述出来 ...
- Spring4学习回顾之路11-AOP
Srping的核心除了之前讲到的IOC/DI之外,还有一个AOP(Aspect Oriented Programming:面向切面编程):通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术 ...
- 网络流基础&网络流24题
网络最大流 dinic+当前弧优化. const int N=10007,M=100007,inf=1e9; int s,t,head[N],ver[M],edge[M],Next[M],tot=1, ...
- opencv实现人脸识别(五) 运用tkinter进行GUI绘制 整合人脸识别模块
因为之前学习过tkinter库,所以在学习了人脸识别模块的编写后, 打算绘制一个简单的GUI来应用人脸识别功能. 主界面如下所示: 签到打开在点开后直接进行人脸识别,如果成功则自动关闭视频窗口. 录入 ...
- Go语言注意事项
必须恰当导入需要的包,缺少了必要的包或者导入了不需要的包,程序都无法编译通过.这项严格要求避免了程序开发过程中引入未使用的包(译注:Go语言编译过程没有警告信息,争议特性之一 import 声明必须跟 ...
- 【AC自动机】文本生成器
[题目链接] https://loj.ac/problem/10063 [题意] 给出长度为m,n个模式串,请问只要长度为m的串中有一个模式串就算是可读. [分析] 其实如果直接分析全部可读的情况,一 ...