c#匿名方法的一个注意点

在看Artech的博客时发现他的这篇难道调用ThreadPool.QueueUserWorkItem()的时候,真是必须调用Thread.Sleep(N)吗? 讲到的一个匿名方法造成的问题,在文章后面,有老赵的回复,并且给出了解决方案(查看老赵的“警惕匿名方法造成的变量共享”)。其实不止匿名方法有这个困扰,我们在操作集合的时候,都应该全面考虑到”变量共享“问题。下面就贴一下自己加了几行注释的Artech的源码,从我自己的角度来分析一下:

代码
   class Program
    {
        
static void Main(string[] args)
        {
            List
<Action> actions = new List<Action>();
            actions.Add(() 
=> Console.WriteLine("A1"));
            actions.Add(() 
=> Console.WriteLine("A2"));
            actions.Add(() 
=> Console.WriteLine("A3"));
            actions.Add(() 
=> Console.WriteLine("A4"));
            
foreach (var action in actions)
            {
                
//var tmpAction = action; //线程执行这个委托方法就输出正常
                
//ThreadPool.QueueUserWorkItem(state => tmpAction(), null);

                ThreadPool.QueueUserWorkItem(state 
=> action(), null);
                
//Thread.Sleep(1); //不管有没有这一行  都是有问题的
            }
            Console.Read();
        }
    }

 运行后,我们看到的结果和我们理想的相差甚远(加上Thread Sleep(1)那一行运行结果有时也不全是我们想要的结果)。
其实我们完全可以这样理解:在foreach循环的时候,action是一个委托方法引用,是引用类型,线程执行的时候,都将执行action变量所在的同一引用地址上的委托方法。而我们将action赋值给一个中间变量tmpAction后,每循环一次,就相当于在内存上重新分配了一段空间,然后线程执行一个新引用地址上的委托方法,这就避免了老赵所说的“匿名方法造成的变量共享”。
ps:我在早前一篇博客里讲到匿名方法的“一个需要注意的地方”的时候也提到了这一点,不知各位是否赞同。

posted on 2009-12-05 12:36  JeffWong  阅读(689)  评论(2编辑  收藏  举报