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:我在早前一篇博客里讲到匿名方法的“一个需要注意的地方”的时候也提到了这一点,不知各位是否赞同。






本文转自JeffWong博客园博客,原文链接:http://www.cnblogs.com/jeffwongishandsome/archive/2009/12/05/1559998.html,如需转载请自行联系原作者

目录
相关文章
|
2月前
|
开发框架 .NET 程序员
C# 去掉字符串最后一个字符的 4 种方法
在实际业务中,我们经常会遇到在循环中拼接字符串的场景,循环结束之后拼接得到的字符串的最后一个字符往往需要去掉,看看 C# 提供了哪4种方法可以高效去掉字符串的最后一个字符
253 0
|
1月前
|
编译器 C#
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
115 65
|
5月前
|
数据采集 数据可视化 测试技术
C#生成Selenium测试报告:实用方法与技巧
在C#中使用Selenium进行自动化测试时,结合代理IP和ExtentReports能增强测试安全性和报告质量。安装必备工具如Selenium WebDriver、NUnit和ExtentReports。在测试设置中,配置代理(如亿牛云爬虫代理)以隐藏IP,通过ChromeOptions定制UserAgent,并添加Cookie。测试代码示例展示了如何打开网页、执行搜索并生成详细的测试报告。使用ExtentReports可创建可视化测试结果,便于团队分析。
C#生成Selenium测试报告:实用方法与技巧
|
3天前
|
C# UED SEO
C# 异步方法async / await任务超时处理
通过使用 `Task.WhenAny`和 `Task.Delay`方法,您可以在C#中有效地实现异步任务的超时处理机制。这种方法允许您在指定时间内等待任务完成,并在任务超时时采取适当的措施,如抛出异常或执行备用操作。希望本文提供的详细解释和代码示例能帮助您在实际项目中更好地处理异步任务超时问题,提升应用程序的可靠性和用户体验。
12 3
|
1月前
|
存储 C#
【C#】大批量判断文件是否存在的两种方法效率对比
【C#】大批量判断文件是否存在的两种方法效率对比
33 1
|
1月前
|
C#
C#的方法的参数传递
C#的方法的参数传递
14 0
|
1月前
|
数据可视化 程序员 C#
C#中windows应用窗体程序的输入输出方法实例
C#中windows应用窗体程序的输入输出方法实例
40 0
|
2月前
|
C#
C#一分钟浅谈:Lambda 表达式和匿名方法
本文详细介绍了C#编程中的Lambda表达式与匿名方法,两者均可用于定义无名函数,使代码更简洁易维护。文章通过基础概念讲解和示例对比,展示了各自语法特点,如Lambda表达式的`(parameters) =&gt; expression`形式及匿名方法的`delegate(parameters)`结构。并通过实例演示了两者的应用差异,强调了在使用Lambda时应注意闭包问题及其解决策略,推荐优先使用Lambda表达式以增强代码可读性。
41 8
|
3月前
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
75 0
|
3月前
|
C#
C# async await 异步执行方法
C# async await 异步执行方法
51 0