委托

​ 委托可以说是方法的集合,里面放着方法列表,当调用的时候就会调用全部的方法列表

​ 个人理解 :

  • 当声明和创建时委托时, 它是个 对象
  • 当使用委托,调用方法时,它是个 方法

声明委托类型

delegate void MyDel(int x)

对比一下filed字段声明

int  count = 5;

​ 可以知道delegate 对应 int , 它是 种类型,void MyDel( int x ) 对应count

创建对象

private delegate void MyDel(int x);
MyDel requestHandler =new MyDel(addCount); private void addCount(int x){
x+=x;
}

为委托类型里面添加方法

requestHandler += addCount1;
requestHandler += addCount2;
//调用
requestHandler(5); private void addCount1(int x){ }
private void addCount2(int x){ }

​ 委托类型要是有返回值,那么最后一个方法执行的返回值就是就结果

委托方法内存放的是匿名方法

​ 委托里的匿名方法的作用是初始化委托,就是方法列表中的方法是没有名字的

MyDel requestHandler;
requestHandler = delegate(int x){
x+=x;
}

匿名方法捕获变量

​ 从这里也可以知道匿名方法的声音应该是与int y =5 ;同级或是比它低层次

MyDel requestHandler;
int y=5;
requestHandler = delegate(int x){
x=y+5;
}

委托 + lamb表达式

MyDel requestHandler;
MyDel requestHandler1;
//匿名方法
requestHandler = delegate(int x) {x+20;}
requestHandler1 = x => {x+20;}

事件

​ 联想一下观察者模式,当某一状态触发的时候,就会触发一些对象的方法,这个过程就像是委托一样调用方法列表一样,发布者就是一个委托对象,订阅者就是在里面的方法列表. 和方法,属性一样,事件event 是类或结构的成员,所以我们不能在一段可执行代码中声明事件,事件的初始值为null

​ 个人理解:

  • event 的声明为事件的关键字,和方法,属性,字段平级

  • 当在调用时事件就是调用方法

    ​对于事件的私有委托, 需要注意的事项:

直接上代码

delegate void CountDel();
class Incrementer {
//事件本身就是个观察者,一旦被触发,就马上通知订阅者
public event CountDel MyEvent; //这是某个触发点
public void DoCount (){
for(int i =1;i<100;i++){
if(i%12==0 && MyEvent!=null){
MyEvent();
}
}
} } //订阅者
class Dozens{
public int DozenCount {get;private set} public void Dozens(Incrementer incrementer){
incrementer +=AddDozenCount;
} public void AddDozenCount(){
DozenCount++;
}
} class Test {
Incrementer inc = new Incrementer();
Dozens dozens = new Dozens(inc);
inc.DoCount();
}

标准事件(EventHandler)

​ .NET 环境中定义的标准事件,定义如下:

public event delegate EventHandler (object sender , EventArgs args)

​ 从形参名字可以看出第一个参数表示发送者,第二个参数传递一些信息

通过扩展EventArgs 来传递数据

​ 需要配置泛型委托来实现,上代码

//自定义EventArgs
class MyEventArgs : EventArgs{
public int Anum{
get;set;
}
} class Incrementer {
//事件本身就是个观察者,一旦被触发,就马上通知订阅者
public event EventHandler<MyEventArgs> MyEvent; //这是某个触发点
public void DoCount (){
MyEventArgs eventArgs = new MyEventArgs();
for(int i =1;i<100;i++){
if(i%12==0 && MyEvent!=null){
eventArgs.Anum = i;
MyEvent(this,eventArgs);
}
}
} } //订阅者
class Dozens{
public int DozenCount {get;private set} public void Dozens(Incrementer incrementer){
incrementer +=AddDozenCount;
} public void AddDozenCount(object obj,MyEventArgs e){
Console.writeLine("当数到{0}时,增加一",e.Anum);
DozenCount++;
}
} class Test {
static void main (){
Incrementer inc = new Incrementer();
Dozens dozens = new Dozens(inc);
inc.DoCount();
Console.writeLine("共记录了{0}次",dozens.DozenCount);
}
}

异步

​ 异步是什么 ? 例如你去买奶茶,店员说请稍等,你在店员做奶茶的同时,你可以刷刷朋友圈,做其他事,等奶茶做好了,你再付钱,完成了买奶茶这件事。对于我来说,店员调配奶茶就是一个异步方法。异步不一定就是在其他线程执行,也可能在同个线程执行

​ 首先看一下异步方法

class Today{
async Task<Tea> MakeTeaAsync (){
Console.Writeline("开始做奶茶呀!");
Salewoman girl = new Salewomen();
Tea tea = await girl.makeTea();
return tea;
}
} class Test {
public static void main(string args){
Today to = new Today();
Task<Tea> teaTask = to.MakeTeaAsync();
Console.writeLine(teaTask.Tostring());
} }

​ 异步方法有三种返回值void,Task<T>,Task ,获取异步方法的结果调用Task.Result.调用方法的接收都是用Task 对象接收.

​ 如果我们的异步不需要异步的数据,那么可以一直执行下去,但是当并行的线程需要异步的数据仍然会阻塞等待

class Test{
public static void main (){
Task<int> task = CountAsync();
...
//下面需要用到异步的数据,那么加入异步没完成,此处会阻塞
Console.wrintLine("结果为: "+task.Result); //异步方法另外两种返回值
Task task = CounterAsync1();
Task task = CounterAsync2();//或直接调用异步方法 CounterAsync();
}
} private async Task<int> CountAsync(){
int result = await SocketHelper.get();
return result;
} private async Task CountAsync1(){
int result = await SocketHelper.getAgain();
Console.writeLine("hello world !");
} private async void CountAsync2(){
int result = await SocketHelper.getAgain1();
}

​ 那么有没有,解决方法呢?我就是不想阻塞. 有, 回调.稍后介绍

异步方法在新线程执行

​ 异步默认情况下是当前线程执行的,当需要新开线程执行时,直接使用lamb 表达式

private async Task<int> CountAsync(){

   int result = await Task.Run(new Fun<int>(Get));
//lamb表达式,
int result1 = await Task.Run(()=>{
return SocketHelper.get(num);
}); return result;
} private int GetCount(int num){
return SocketHelper.get(num);
}

Task.Run( ) 返回的结果有TaskTask<TResult>两种,形参用到的类有Action , Fun<TResult>Fun<Task>,其中Fun<Task>不讲,详细方法如下 , (学习两种简单的)

public static Task Run (Action action) {}

public static Task<TResult> Run (Func<TResult> func) {}

ActionFunc<TResult> 是两个委托, 它们的方法列表签名是不需要参数,返回值一个为void ,另外一个为传入的泛型,上面的例子

//委托Action
public delegate void Action(); //委托Func<TResult>
public delegate TResult Func<out TResult>(); //创建匿名委托对象(方法列表)内添加Get方法
int result = await Task.Run(new Fun<int>(Get));

​ 假如我需要个执行的任务是需要传递参数的,那么可以这样写

int reusult = await Task.Run(()=>Get(5,6));

​ 上面的例子()=>Get(5,6)是创建了Func<TResult>对象,并且为这个委托(方法列表)内添加了一个匿名的不需参数的方法,在这个匿名方法内执行Get(5,6)

异步方法中取消任务

​ 同样的是Task.Run( )方法,这里用到两个类,CancelationTokenCancelationTokenSource ,后者从名字可以看出是产生CancelationToken的,而使用CancelationToken去取消任务实际是令CancelationToken的属性IsCancelationRequested true

public static Task Run (Action action , CancelationToken token) {}

public static Task<TResult> Run (Func<TResult> func , CancelationToken token ) {}
例子
class Test {
public void main(){
CancelationTokenSource source = new CancelationTokenSource();
CancelationToken tokent = source.token; MyClass my = new MyClass();
Task task = my.CancelAsync(token); //task.wait();
//token.cancel;
task.wait();
Console.writeLine("结束");
}
} class MyClass {
public async void CancelAsync(CancelationToken token){
if(IsCancelationRequested)
return;
Task task = await Task.Run(new Fun(TestTask),token); } public void TestTask(){
Console.writeLine("开始");
for(int i = 0 ; i < 5 ; i++){
if(IsCancelationRequested){
return;
} Thread.sleep(1000);
Console.writeLine("{0} of counts is completed",i+1); }
}
}
//带注释运行
开始
1 of counts is completed
2 of counts is completed
3 of counts is completed
4 of counts is completed
5 of counts is completed
结束 //不带注释运行
开始
1 of counts is completed
2 of counts is completed
3 of counts is completed
结束

异步中处理异常

await语句中直接加上try..catch

等待异步完成后再继续运行

//等待单个任务完成后继续执行
Task.Wait() //等待一组任务完成后
Task[] tasks = new Task[]{t1,t2};
Task.WaitAll(tasks);

委托异步编程

​ 当委托中只有一个方法(方法列表里只要一个方法)时可以使这个方法在另外的线程(线程池中的线程)中异步执行,使用的方法是委托的BeginInvoke ,当希望获取到异步的结果时可以检查BeginInvoke返回的IAsyncResultIscompleted属性,或是调用委托的EndInvoke来等待异步的完成.有三种异步编程方式。分别是轮询, 一直等待和回调。

namespace Common.Been
{ internal delegate int MyDelegate(string milk, string tea);
class Test
{
private MyDelegate del = delegate(string milk, string tea)
{
Console.WriteLine(milk + " " + tea);
return milk.Length + tea.Length;
}; public void MyCallback(IAsyncResult asyncResult)
{
AsyncResult AsyncCallback = (AsyncResult) asyncResult.AsyncState;
MyDelegate callDelegate = (MyDelegate) AsyncCallback.AsyncDelegate;
int result = callDelegate.EndInvoke(asyncResult);
//这里在进行一些其他操作 }
public void main()
{
string m = "cow milk";
string t = "black tea"; //public IAsyncResult BeginInvoke(string milk, string tea, AsyncCallback callback, object state)
//不使用回调的情况
IAsyncResult AsyncResult = del.BeginInvoke(m, t, null, null);
int result = del.EndInvoke(AsyncResult); //public delegate void AsyncCallback(IAsyncResult ar);
//使用回调
IAsyncResult AsyncResult1 = del.BeginInvoke(m, t, new AsyncCallback(MyCallback), del); }
} }

BeginInvoke返回一个IAsyncResult对象,它实际上是个AsyhcResult对象,他们的关系是怎么样的呢?

​ 其中,AsyncDelegate保持着调用BeginInvoke方法的委托引用,AsyncState保存着是BeginInvoke方法的第四个参数.

计时器

​ 周期执行的异步类,同样它也是从线程池内拿取线程执行方法,同时可以传入回调

class Test {
///
///第二个参数: 传给回调的对象引用
///第三个参数: 多久后开始
///第四个参数: 每过多久循环
public void main(){
//public Timer( TimerCallback callback, object state, int dueTime, int period)
//public delegate void TimerCallback(object state);
string giveCallback = "love you ";
Timer timer = new Timer(new TimerCallback(TimeCallback), giveCallback, 2000, 3000); } private void TimeCallback(object obj)
{
string whatYouGive = (string) obj;
}
}

C# 委托,事件, 异步的更多相关文章

  1. 【温故而知新-万花筒】C# 异步编程 逆变 协变 委托 事件 事件参数 迭代 线程、多线程、线程池、后台线程

    额基本脱离了2.0 3.5的时代了.在.net 4.0+ 时代.一切都是辣么简单! 参考文档: http://www.cnblogs.com/linzheng/archive/2012/04/11/2 ...

  2. C# ~ 从 委托事件 到 观察者模式 - Observer

    委托和事件的部分基础知识可参见 C#/.NET 基础学习 之 [委托-事件] 部分: 参考 [1]. 初识事件 到 自定义事件: [2]. 从类型不安全的委托 到 类型安全的事件: [3]. 函数指针 ...

  3. C#委托,事件理解入门 (译稿)

    原文地址:http://www.codeproject.com/Articles/4773/Events-and-Delegates-Simplified 引用翻译地址:http://www.cnbl ...

  4. 关于ios使用jquery的on,委托事件失效

    $('.parents').on("click",'.child',function(){}); 类似上面这种,在ios上点击"child"元素不会起作用,解决 ...

  5. Observer设计模式中-委托事件-应用在消息在窗体上显示

    Observer设计模式:监视者模式.在类中的方法中处理的结果或者消息通过事件委托 的方式发送给主窗体. 因为在其它类中直接访问主窗体类,显示内容是不能直接调用控件赋值的,当然也有别的类似查阅控件名, ...

  6. Asp.net用户控件和委托事件

    在Asp.net系统制作过程中,门户类型的网站,我们可以用DIV+CSS+JS+Ajax全部搞定,但是一旦遇到界面元素比较复杂的时候,还是UserControl比较方便一些,各种封装,各种处理,然后拖 ...

  7. jQuery里面的普通绑定事件和on委托事件

    以click事件为例: 普通绑定事件:$('.btn1').click(function(){}绑定 on绑定事件:$(document).on('click','.btn2',function(){ ...

  8. c#基础学习笔记-----------委托事件

    这里有一个比较简单的委托实例应用(跨窗体操作控件) http://blog.csdn.net/bdstjk/article/details/7004035 还有一个比较详细的介绍并深入理解委托事件的讲 ...

  9. C#委托的异步调用1

    本文将主要通过“同步调用”.“异步调用”.“异步回调”三个示例来讲解在用委托执行同一个“加法类”的时候的的区别和利弊. 首先,通过代码定义一个委托和下面三个示例将要调用的方法: /*添加的命名空间 u ...

  10. C#委托的异步调用

    本文将主要通过“同步调用”.“异步调用”.“异步回调”三个示例来讲解在用委托执行同一个“加法类”的时候的的区别和利弊. 首先,通过代码定义一个委托和下面三个示例将要调用的方法: /*添加的命名空间 u ...

随机推荐

  1. 2018.11-2019.1的随记|NOIP的考后随记

    就是日记吧?(这里就是写一些乱七八糟的东西qwq,当作自己的零散想念吧 1.24 今天跟着BLUESKY他们的视频一起领略了一下远在广州的CCF冬令营开幕式,看着ljh的拍的照片也体验了一下RM冬令营 ...

  2. 根据浏览器判断是否为Android、ios或微信环境

    写h5页面时经常有业务逻辑需要判断页面所处的环境,这时我们可以通过navigator对象来获取浏览器相关信息加以判断,方法如下: let ua = navigator.userAgent; let i ...

  3. 2016级算法第二次上机-F.ModricWang's Number Theory II

    891 ModricWang's Number Theory II 思路 使得序列的最大公约数不为1,就是大于等于2,就是找到一个大于等于2的数,它能够整除序列中的所有数. 考虑使得一个数d整除数组中 ...

  4. 01迷宫 BFS

    题目描述 有一个仅由数字000与111组成的n×nn \times nn×n格迷宫.若你位于一格0上,那么你可以移动到相邻444格中的某一格111上,同样若你位于一格1上,那么你可以移动到相邻444格 ...

  5. ZOJ - 3649 树上倍增

    题意:给出一个图,先求出最大生成树,然后多次询问树上路径\(u→v\)的有向最大极差\(max(a_i-a_j),i>j\),其中\(i\)和\(j\)指代节点在路径中出现的顺序 极差具有单调性 ...

  6. 剑指offer——面试题25:合并两个 排序的链表

    自己答案: ListNode* MergeTwoSortedList(ListNode* pHead1,ListNode* pHead2) { if(pHead1==nullptr&& ...

  7. Vue项目中使用HighChart

    记:初次在Vue项目中使用 HighChart 的时候要走的坑 感谢这位哥们的思路 传送门 Vue-cli项目使用 npm install highcharts --save 让我们看看 highch ...

  8. javascript 将 table 导出 Excel ,可跨行跨列

    <script language="JavaScript" type="text/javascript"> //jQuery HTML导出Excel ...

  9. c# 引用类型对象的深拷贝

    c#中的对象大体分为值类型和引用类型,值类型大致包括 int, struct等,引用类型大致包括 自定义Class,object 等.string属于特殊的引用类型,不在本文的讨论之内. 值类型直接存 ...

  10. 赋值运算与深浅copy

    1.复制运算 l1 = [1,2,3,['a','b']] l2 = l1 l1[0] = 111 print(l1) # [111, 2, 3, ['a', 'b']] print(l2) # [1 ...