一、委托
委托是一种用于封装命名和匿名方法的引用类型。
把方法当参数,传给另一个方法(这么说好理解,但实际上方法不能当参数,传入的是委托类型),委托是一种引用类型,委托里包含很多方法的引用
创建的方法和声明的委托返回值类型相同,参数个数相同,参数类型相同时。 这个方法就满足属于这个委托(创建的方法是 public 或者是static 都没影响,只要前三项满足即可)
用普通方式创建一个委托
//声明委托(声明委托的位置也可以在class内部)
public delegate string del(double a, double b);
class Program
{
//定义一个求和方法
public string sumResult(double a, double b)
{
double sum = a + b;
string str1 = Convert.ToString(sum);
string str2 = "结果等于" + str1;
return str2;
}
//定义一个乘积方法
public string multiplyResult(double a, double b)
{
double sum = a * b;
string str1 = Convert.ToString(sum);
string str2 = "结果等于" + str1;
return str2;
}
static void Main(string[] args)
{
Program p = new Program();
//加载一个相加方法
del sr = new del(p.sumResult);
//可以简便方式加载一个方法
del mr = p.multiplyResult;
//调用委托对象传入参数,用string类型接收结果
string str1 = sr(, );
string str2 = mr(, );
Console.WriteLine(str1);
Console.WriteLine(str2);
Console.ReadKey();
}
}
引用静态方法的方式
//声明委托
public delegate string del(double a, double b);
//定义一个静态方法
public static string sumResult(double a, double b)
{
double sum = a + b;
string str1 = Convert.ToString(sum);
string str2 = "结果等于" + str1;
return str2;
}
static void Main(string[] args)
{
//用普通方式创建一个委托对象
del sr = sumResult; //用string类型接收结果
string str = sr(2.5, 3.5);
Console.WriteLine(str);
Console.ReadKey();
}
把多个方法存到一个数组,利用循环来调用不同方法
//定义个委托,传入一个double参数,返回一个double。
delegate int delInt(int a);
class Program
{
static void Main(string[] args)
{
//定义并初始化一个数组。数组的类型为委托类型 --没想到还以用委托当类型
delInt[] delArray = { sumMethod.addTwo, sumMethod.XTwo};
for (int i = ; i < delArray.Length; i++)
{
Console.WriteLine("循环{0}",i);
display(delArray[i], );
display(delArray[i], ); }
Console.ReadKey();
}
//显示的方法
static void display(delInt del,int a)
{
int result = del(a);
Console.WriteLine("传入{0},计算结果为{1}", a, result);
}
}
//计算类
class sumMethod
{
//加2
public static int addTwo(int a)
{
return a + ;
}
//乘2
public static int XTwo(int a)
{
return a * ;
}
}
结果
到此为止以上的例子不能说明委托的意义,这些例子都能在不适用委托的情况下编写。
代表委托用法的例子
...
...
...
二、委托的多播
包含多个方法的委托叫做多播。
委托对象可使用 "+" 运算符进行合并。一个合并委托调用它所合并的两个委托。只有相同类型的委托可被合并。"-" 运算符可用于从合并的委托中移除组件委托。
调用多播可以按顺序连续调用多个方法,委托的返回类型必须是void,否则只能得到委托调用最后一个方法的结果。
delegate void del(int sum);//声明一个委托
class MyClass
{
public void shuchuB(int x)
{
Console.WriteLine(10 * x);
Console.ReadLine();
}
}
class Program
{
static void shuchuA(int x)
{
Console.WriteLine(20 * x);
Console.ReadLine();
}
static void Main(string[] args)
{
MyClass mc = new MyClass();
del a = shuchuA; //创建一个委托实例,持有一个静态方法
del b = mc.shuchuB; //持有一个实例方法
del c = a + b; //持有以上两个方法
c(5);
}
}
如果
del c = b+a+b;
则
还有自加自的方式,如果一个del里有两个相同的方法,他会优先删除后进的。(后进先出)
del b += a;
del b -= a;
多播委托可能遇到的问题
如果委托调用的其中一个方法抛出异常,整个迭代就会停止
static void Main(string[] args)
{
//当一个委托没有参数也没有返回值时,就可以直接使用Action委托,无需声明
Action action = one;
action += two;
try
{
action();
}
catch (Exception)
{
Console.WriteLine("exception");
}
Console.ReadKey();
}
static void one()
{
Console.WriteLine("one");
throw new Exception("Error");
}
static void two()
{
Console.WriteLine("two");
}
为避免此问题,需要迭代方法列表
static void Main(string[] args)
{
//当一个委托没有参数也没有返回值时,就可以直接使用Action委托,无需声明
Action action = one;
action += two;
//委托的GetInvocationList方法会按照加入顺序返回一个委托数组
Delegate[] dels = action.GetInvocationList();
foreach (Action act in dels)
{
try
{
act();
}
catch (Exception)
{
Console.WriteLine("exception");
}
}
Console.ReadKey();
}
三、泛型委托
1
2.
Action 简化了delegate的写法
Action返回类型必须是void,可以1-16任意参数类型<参数类型1,参数类型2,..>
也可以传不同参数类型
用var快速定义
3.有返回类型用Func
最后一个参数类型为返回类型
三、匿名函数
匿名方法有两种:匿名方法、Lambda表达式
在 2.0 之前的 C# 版本中,声明委托的唯一方法是使用命名方法。
C# 2.0 引入了匿名方法,而在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方法,作为编写内联代码的首选方式.
1.匿名方法
匿名方法比普通的委托写起来简练易读,在只一次调用方法时使用起来比较方便
语法:在创建委托实例的同时紧接着用花括号写入方法
public delegate string del(参数1,参数2,...);
A a =new A(参数1,参数2,...)
{
.....
.....
return string类型;
};
注意几点:
(1)A 是一个委托
(2)创建委托实例时参数的个数和类型都必须与声明委托时一致
(3)花括号里的返回类型必须要与声明的返回类型一致
(4)末尾别忘加 ;
用匿名方式创建一个委托对象
class Program
{
//也可以外部声明
public delegate string del(double a, double b);
static void Main(string[] args)
{
Program p =new Program();
//用匿名方式创建一个委托对象
del sr = delegate(double a, double b)
{
double sum = a + b;
string str1 = Convert.ToString(sum);
string str2 = "结果等于" + str1;
return str2;
};
//用string类型接收结果
string str = sr(2.5, 3.5);
Console.WriteLine(str);
Console.ReadKey();
}
}
2、用lambda方法实现
通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数。 Lambda 表达式对于编写 LINQ 查询表达式特别有用。
调用时声明的方法,用一次就没。不用再单独声明个方法
格式:
若要创建 lambda 表达式,需要在 Lambda 运算符 =>左侧指定输入参数(如果有),然后在另一侧输入表达式或语句块。
例如,lambda 表达式 x => x * x
指定名为 x
的参数并返回 x
的平方值
单行lambda 表达式
class Program
{ public delegate double del(double a, double b);
static void Main(string[] args)
{
Program p = new Program();
//用lambda表达式的方法
del sr = (a, b) => a + b;
//传入多个参数要加括号,如果是一个参数可以写成
//del sr = a => a * a; //开头注意声明的类型和下面这个接收的变量都是double
double d = sr(2.5, 3.5);
Console.WriteLine(d);
Console.ReadKey();
}
}
多行lambda 表达式
单行表达式省略了return、花括号和分号。用多行表达式时都要补充上。
Program p = new Program();
del sr = (a, b) =>
{
return a + b;
};
泛型Lambda,可以重用
语法糖可省略 lambda参数类型
语法糖 不需要再创建实例,省略了 new Func<int,int,int>
这个是最常用的方式
进阶
泛型委托类型推断,省略了 <int>
3.闭包
。。。。。
委托隐式异步调用
使用接口取代委托减少复杂性和安全性(java没有委托,就是用接口的方式)
四、事件
事件是一种类似于订阅/发布的机制。
把订阅当成一个方法,每次一订阅就会存一个方法进入委托中。等到发布的时候,一次性的发消息给哪些订阅。
例如:
日本丰田公司2017年生产了三款新车,(汉兰达2018,凯美瑞2018,雷凌2018)。
家住天津王兰庄附近的‘大刘’和‘小明’从网上看到消息后给王兰庄广汽丰田4S点打电话了解这三款车
4S点销售员告诉他们新车还没到货,让他们留下联系方式,等车到店了给你们发短信通知他们来店里看实车。
创建一个控制台程序
再新建一个事件发布类:ReleaseEventArgs
再新建一个事件监听类:Consumer
class ReleaseEventArgs : EventArgs
{
public ReleaseEventArgs(string car)
{
this.Car = car;
}
public string Car { get; set; } public class Shop
{
//
public event EventHandler<ReleaseEventArgs> NewCarClass;
public void NewCar(string car)
{
Console.WriteLine("{0}",car);
raise(car);
}
protected virtual void raise(string car)
{
EventHandler<ReleaseEventArgs> newCarClass = NewCarClass;
if (newCarClass != null)
{
newCarClass(this, new ReleaseEventArgs(car));
}
}
}
}
class Consumer
{
private string name; public Consumer(string name)
{
this.name = name;
}
public void CarArriving(object sender, ReleaseEventArgs e)
{
Console.WriteLine("尊敬的{0},王兰庄4S点提示您:{1}到货了",name,e.Car);
}
}
class Program
{
static void Main(string[] args)
{
var shop = new ReleaseEventArgs.Shop();
var daliu = new Consumer("大刘");
var xiaoming = new Consumer("小明");
shop.NewCarClass += daliu.CarArriving;
shop.NewCarClass += xiaoming.CarArriving;
shop.NewCar("汉兰达2018");
shop.NewCarClass -= daliu.CarArriving;
shop.NewCar("凯美瑞2018");
var zhoujie = new Consumer("周杰");
shop.NewCarClass += zhoujie.CarArriving;
shop.NewCar("雷凌2018"); Console.ReadKey();
}
}
https://www.cnblogs.com/gq0324/p/8177799.html
事件
using System; namespace ConsoleApp4
{
class Program
{
static void Main(string[] args)
{
Business bus = new Business();
bus.Price = ;
bus.Changed += Test_Changed; bus.Price = ;
bus.Price = ;
Console.WriteLine("Hello World!"); void Test_Changed(object sender, ChangeEventArgs e)
{
if ((e.newPrice - e.oldPrice) > )
{
Console.WriteLine("大于10");
}
}
}
} //标准事件模式
//一个继承事件类的子类
public class ChangeEventArgs : EventArgs
{
public int oldPrice;
public int newPrice;
//ctor + tab
public ChangeEventArgs(int oldPrice, int newPrice)
{
this.oldPrice = oldPrice;
this.newPrice = newPrice;
}
} public class Business
{
int price; public event EventHandler<ChangeEventArgs> Changed; protected virtual void OnChange(ChangeEventArgs e)
{
Changed?.Invoke(this, e);
} public int Price
{
get { return price; }
set
{
if (price == value) return;
int oldPrice = price;
price = value;
OnChange(new ChangeEventArgs(oldPrice, price));
}
}
}
}
------------------------------------------------
为什么要用委托?
//定义
public delegate void del(int value);
实际上相当于:定义了一个类
public class del:System.MulticastDelegate
{
//构造函数
public del(Object @object, IntPtr method);
//
public virtual void Invoke(Int32 value);
//回调方法的异步回调
public virtual IAsyncResult BeginInvoke(Int32 value, AsyncCallback callback, Object @object);
//回调方法的异步回调
public virtual void EndInvoke(IAsyncResult result);
}
异步调用完成时执行回调方法
异步启动委托, 参数与要执行的方法的参数相同,另加两个可选参数
第一个参数是一个 AsyncCallback 委托,此委托引用在异步调用完成时要调用的方法。
第二个参数是一个用户定义的对象,该对象将信息传递到回调方法。
BeginInvoke
将立即返回,而不会等待异步调用完成。
BeginInvoke
返回可用于监视异步调用的进度的 IAsyncResult。
委托对象.BeginInvoke();
EndInvoke
方法用于检索异步调用的结果,它可以在调用 BeginInvoke
之后的任意时间调用
如果异步调用尚未完成,那么 EndInvoke
将阻止调用线程,直到完成异步调用
---------------------------------------
(28)C#委托,匿名函数,lambda表达式,事件的更多相关文章
-
委托-异步调用-泛型委托-匿名方法-Lambda表达式-事件【转】
1. 委托 From: http://www.cnblogs.com/daxnet/archive/2008/11/08/1687014.html 类是对象的抽象,而委托则可以看成是函数的抽象.一个委 ...
-
【Unity|C#】基础篇(9)——匿名函数 / Lambda表达式
[学习资料] <C#图解教程>(第13章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu. ...
-
匿名函数 lambda表达式(lambda expression)
阅读g2log时,发现有两行代码居然看不懂. 1. auto bg_call = [this, log_directory]() {return pimpl_->backgroundChang ...
-
C#多线程+委托+匿名方法+Lambda表达式
线程 下面是百度写的: 定义英文:Thread每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程.进程也可能是整个程序或者是部分程序的动态执行.线程是一组指令的集合,或者是程序的特殊段,它 ...
-
Qt中使用匿名函数lambda表达式
一.为什么要使用匿名函数lamdba 首先,lambda表达式可以使代码变得简单,C++中,一个lambda表达式表示一个可调用的代码单元.如代码: #include <QCoreApplica ...
-
Python匿名函数——lambda表达式
如果要定义的函数很简单,一个return语句就能搞定,可以使用lambda表达式来定义, lambda表达式的语法如下: lambda parameters: expression lambda表达式 ...
-
python做中学(八)匿名函数lambda的用法
匿名函数,顾名思义即没有名称的函数,和def定义的函数的最大区别在于匿名函数创建后返回函数本身(即匿名函数不需要return来返回值),表达式本身结果就是返回值,而def创建后则赋值给一个变量名,在P ...
-
C# delegate event func action 匿名方法 lambda表达式
delegate event action func 匿名方法 lambda表达式 delegate类似c++的函数指针,但是是类型安全的,可以指向多个函数, public delegate void ...
-
『Python基础-14』匿名函数 `lambda`
匿名函数和关键字lambda 匿名函数就是没有名称的函数,也就是不再使用def语句定义的函数 在Python中,如果要声匿名函数,则需要使用lambda关键字 使用lambda声明的匿名函数能接收任何 ...
随机推荐
-
【Alpha】Daily Scrum Meeting第八次
一.本次Daily Scrum Meeting主要内容 抓紧冲刺(接下去两天都在下午增加一个小会议) 剩余任务的概况 二.项目进展 学号尾数 今日已完成任务 接下去要做 502 无 将数据库的数据转换 ...
-
Android基础问题汇总
一.android:gravity 和android:layout_gravity的区别: android;gravity是自己的内容相对于自己的控件的位置,而android:layout_gravi ...
-
poj 3250 Bad Hair Day (单调栈)
Bad Hair Day Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 14883 Accepted: 4940 Des ...
-
HTML 锚点链接,链接到同一个页面的不同位置
<html> <head> <title></title> </head> <body> ...
-
PL/SQL基本概念
首先明确PL/SQL主要作用作用: SQL语言适合管理关系型数据库但是它无法满足更复杂的数据处理,所以产生PLSQL.PLSQL用户创建存储过程.函数.触发器.包及用户自定义的函数. 特点: PLSQ ...
-
switch case异常处理机制
public class T3{ public static void main(String[] args) { try{ String kc=""; System.out.pr ...
-
Nginx配置参数中文说明
#定义Nginx运行的用户和用户组 user www www; #nginx进程数,建议设置为等于CPU总核心数. worker_processes 8; #全局错误日志定义类型,[ debu ...
-
Spring3+Hibernate4连接Oracle11g数据库参数配置
应用场合:使用SSH框架开发一套应用系统,因为不同的SSH版本+系统架构会导致各种的错误,总结测试了下,成功测试得出本文配置 软件版本:Sping3+Hibernate4+Maven3 主要配置文件内 ...
-
day19常用模块2
常用模块21 shelve模块 也是一种序列化方式 使用方法 1.open sl = shelve.open("shelvetest.txt") ...
-
RoadFlow ASP.NET Core工作流配置文件说明
工作流配置文件及说明如下: { "Logging": { "LogLevel": { "Default": "Warning&qu ...