码迷,mamicode.com
首页 > Windows程序 > 详细

C#中闭包的陷阱

时间:2015-06-08 19:21:54      阅读:292      评论:0      收藏:0      [点我收藏+]

标签:

在最近的项目中,我封装一个异步执行程序的组件。这个组件的功能就是在执行一些耗时的后台操作(比如连数据库读取数据,或者后台进行一些统计计算)的时候不阻塞UI,再弹一个转圈圈的动画告诉用户正在执行后台操作。方法包含三个参数,其中前两个是委托类型,分别是耗时操作的doWork和操作完成后的回调callBack。第三个参数就是弹出的等待动画旁边的提示消息,类似于“正在查找数据,请稍后。。。"之类的文本,由调用方设定。方法代码大概长下面这个样子:

 public static void Run(Action doWorker, Action callBack, string message)
        {
           //todo:method body
        }

因为这个组件我设计成不依赖于任何其他窗体,也就是说这个组件是一个独立的window,而不是作为一个控件插入到其他窗体。在其他任何window里调用都是直接调用这个静态方法即可在调用的window前弹出一个等待窗口,并且调用的地方也没有阻塞。那么问题来了,在这个方法里我怎么才知道是哪个window或者Control在调用呢?我采用的方法是使用doWorker的Target属性来获取当前调用的window,把它赋给组件的Owner,再把组件的启动位置设为Owner的中央即可。代码如下:

this.Owner = doWorker.Target as Window;
if(this.Owner == null)
{
  this.Owner = Window.GetWindow(
doWorker.Target as Control);
}
this.Show();

嗯,大功告成。run起来很顺畅,直到一段代码的出现。那是下面这样一段代码:

var orderTable = grd_Order.DataSource as DataTable;
if(orderTable == null) return;
MsgWindow.Run(()=>{
        DbHepler.Update(orderTable);
    },null,"正在保存数据,请稍后!);

MsgWindow正是我封装的组件的类名。不知道为什么,这段代码调用时钟出错,异常出在Run方法中的这句代码:this.Owner = Window.GetWindow(Traget as Control);

因为调用组件的也许可能不是Window而是一个UserControl,而这句代码正是针对调用方是UserControl的。报的异常是说Window.GetWindow的参数不能为null,也就是说doWorker.Target as Control失败了,doWorker.Target根本不是一个Window,也不是一个Control。这怎么可能?!!代码明明就是写在一个自定义的Control。而且这个Control中还有另外一处也是调用的Run方法,参数都差不多,那里就没问题,运行得很顺畅。为什么就这个调用失败了呢?

经过跟踪调试,发现原来问题出在调用的地方。调的地方传第一个参数doWorker的时候,使用了闭包。在这个匿名方法中引用了外部变量orderTable。我想起之前看过的关于C#闭包的实现原理,其实是将引用的外部对象包装在一个匿名的类里了,引用的外部对象作为这个匿名类的一个成员。在这里,编译的时候C#编译器默默的为orderTable变量生成了一个匿名的类,orderTable作为这个匿名类的成员而保存了下来。要不是这么处理的话,还没来得及执行匿名方法,orderTable就已经超出了作用域而不可访问了。

找到问题根源后,解决方案也就呼之欲出了。其实这里根本用不着闭包,将orderTable放在匿名方法里面即可解决。如下:

if(orderTable == null) return;
MsgWindow.Run(()=>{
        var orderTable = grd_Order.DataSource as DataTable;
        DbHepler.Update(orderTable);
    },null,"正在保存数据,请稍后!);    

 

C#中闭包的陷阱

标签:

原文地址:http://www.cnblogs.com/hengshuo/p/4561584.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!