用户
 找回密码
 立即注册

33

主题

96

帖子

1811

积分

金牌会员

Rank: 6Rank: 6

积分
1811
发表于 2019-7-3 23:45:42
各位专家,

小弟想进一步了解一下回调函数的作用域问题。我知道很多的回调函数都是这么写:e.g

bool flag = false;
this.Client.GetClipboard( ( obj, args) => {
     flag = true;
     if(flag) { // do something }
});

如果写成如下内容, 是不工作的

bool flag = true;
this.Client.GetClipboard(( obj, args) => {
     flag = true;
});

if(flag) { // do something }

我自己的理解是,由于回调函数被触发,和继续向下执行后续内容是同时进行的,因此上面的例子中,如果 if(flag) 判断放置在回调函数之外,它不能被设置成 true

但我想了解的是,回调函数的有效作用域是什么? 我试过了几个办法:

1. 加入延时命令, 这个不行,说明不是由于 回调函数没有执行完成而导致 flag 没能设置成 true

bool flag = false;
this.Client.GetClipboard(( obj, args) => {
     flag = true;
});

Thread.Sleep(1000);
if(flag) { // do something }



2. 将回调函数放入子线程中,也不行,

  private void CallbackFunc()
  {
      this.Client.GetClipboard(( obj, args) => {
         flag = true;
      });
      Thread.Sleep(10000);
  }

ThreadStart Thparm = new ThreadStart( CallbackFunc);
Thread Th1 = new Thread(Thparm);
Th1.Start();
Th1.Join(); // 等待子线程完成后,主线程才继续执行


  if(flag)  { // do something }


3. 如果是在另一个事件中 (比如一个button click 事件),就会发现,该flag已经被正确设置了:

private void Init_Load(object sender, EventArgs e)     // ===> 窗体加载时执行回调
{

    flag = false;
    this.Client.GetClipboard(( obj, args) => {
         flag = true;
     });
}

private void button1_Press(object sender, EventArgs e)
{
    if(flag) { // do something }             // ====> 当触发button1 的click事件后, 在这里看到 flag是设置成true了。
}

我自己不太理解,第2种情况和第三种情况的区别在哪里? 看起来并不是由于第3种情况会在窗体加载和button事件触发之间的间隔比较长而造成的。

因为有时候,回调中需要处理的内容很多,如果全部放在回调函数中处理的话,会导致程序的可读性不好,不知道有没有什么办法来解决这个问题?

谢谢
大杰米
分享至 : QQ空间
0 人收藏
使用道具 举报 回复
发表于 2019-7-4 09:22:13
回调是异步执行的,所以你判断可以放在回调中执行异步回调的文章https://blog.csdn.net/Smobiler/article/details/92974810
使用道具 举报 回复 支持 反对
发表于 2019-7-5 17:43:13
本帖最后由 bigjimmy8257 于 2019-7-5 17:48 编辑
Lula.Jin 发表于 2019-7-4 09:22
回调是异步执行的,所以你判断可以放在回调中执行异步回调的文章https://blog.csdn.net/Smobiler/article/d ...

Luna,

多谢回复,您提供的那个文章我拜读了,里面说的情况我也多少是了解的。 我的疑惑其实是,异步回调发生后,执行的代码中对 变量的改动是如何生效,在哪个范围内生效的。

以this.Client.SetClipboard() 为例,这个操作应该是很快的,我们假设是1ms吧,那么完成后触发异步回调,我在这里面更新了一个变量的值。

那么问题是,我在1s中之后再读这个变量的时候 (比如我在this.Client.SetClipboard() 后面延时使用 Thread.Sleep() 设置1s的阻塞式延时 ),发现该变量并没有得到更新,还是以this.Client.SetClipboard() 执行前的值。 我对此的解读是,异步回调事件中进行的处理,并不会影响到主进程或主线程内的设置,好像是平行宇宙的多个副本。

但是,假如上面的操作是在Form_Load()中进行的,当它结束后,当我再触发另一个事件,比如一个按钮事件的时候,我发现此时,之前异步回调中的设置就生效了。

我不太了解这两种情况有什么不同。同时也想知道,多个副本的不同设置是何时进行的同步?
我没有将判断放入异步回调中执行的原因是,有时候里面放的东西太多,而且又有嵌套其他的异步回调方式,搞得程序可读性不好。因此希望有个办法
解决这个问题。

不知道我问的是不是很清楚。

使用道具 举报 回复 支持 反对
发表于 2019-7-8 10:53:22
bigjimmy8257 发表于 2019-7-5 17:43
Luna,

多谢回复,您提供的那个文章我拜读了,里面说的情况我也多少是了解的。 我的疑惑其实是,异步回调 ...

主要的原因是并不是每执行一条代码,服务端就发送一条给客户端;
客户端发送请求->服务端处理->返回结果给客户端->客户端收到GetClipboard->发送给服务端结果->服务端触发回调;
相当于GetClipboard这个只是要发送给客户端的一个动作,但是这个动作需要在当前方法完全执行完成后才会统一发给客户端;
所以回调还是会在线程休眠后触发。
另外:目前若客户端发送请求->服务端处理->返回结果给客户端 等待时间为10s,若超出报"网络无响应"。
目前确实存在回调嵌套,这个我提交下技术部
使用道具 举报 回复 支持 反对
发表于 2019-7-8 13:04:54
peter.pan 发表于 2019-7-8 10:53
主要的原因是并不是每执行一条代码,服务端就发送一条给客户端;
客户端发送请求->服务端处理->返回结果 ...

清楚了。看起来在这种机制下,暂时还做不到实时的回调。

另外,关于您说的 等待事件10s的情况,加上EnableHeartbeat 的情况下也是这样吗?
使用道具 举报 回复 支持 反对
发表于 2020-7-3 22:20:39
嗯,这个问题问的好,这种深点的问题要多问,我也很关注。多了解原理才能做好功能。怎么没有回复了?
使用道具 举报 回复 支持 反对
发新帖
您需要登录后才可以回帖 登录 | 立即注册