C#:在匿名方法中捕获外部变量

先来一段代码引入主题。如果你可以直接说出代码的输出结果,说明本文不适合你。(代码引自《深入理解C#》第三版)

    class Program
    {
        private delegate void TestDelegate();

        static void Main(string[] args)
        {
            TestDelegate[] delegates = new TestDelegate[2];

            int outside = 0;

            for(int i = 0; i < 2; i++)
            {
                int inside = 0;

                delegates[i] = delegate
                {
                    Console.WriteLine("({0},{1})", outside, inside);
                    outside++;
                    inside++;
                };
            }

            delegates[0]();
            delegates[0]();
            delegates[0]();

            delegates[1]();
            delegates[1]();

            Console.ReadKey();
        }
    }

答案在本文最下方。

先引入两个定义:

1、外部变量:是指作用域内包括匿名方法的局部变量或参数。

2、捕获的外部变量:是指在匿名方法中使用的外部变量。

定义有点抽象,针对上面的代码而言,inside和outside都是匿名方法的外部变量,而inside和outside同样也作为被匿名方法捕获的外部变量,因为在匿名方法体中引用了这两个变量。

而被匿名方法捕获到的是变量本身,而并非变量的值。针对上面的代码而言,执行outside++和inside++时,操作的其实就是外部的inside和outside变量。

至此,我们应该可以得出outside的变化应该是从0到4。

那么程序的输出也应该是这个样子的:(X代码未知)

(0,X)

(1,X)

(2,X)

(3,X)

(4,X)

实际上,在for循环体里面做的东西就是实例化了两个TestDelegate委托对象:delegate[0]和delegate[1]

而循环的执行,实际上会实例化两个名称都为inside的变量。

这两个变量之间没有什么关联,仅仅是名称一样而已。

这两个变量分别作为delegate[0]和delegate[1]的外部捕获变量。也就是delegate[0]和delegate[1]在操作inside时,是互不影响的。

于是,得出答案:

(0,0)

(1,1)

(2,2)

(3,0)

(4,1)

答案

时间: 2024-11-07 20:28:12

C#:在匿名方法中捕获外部变量的相关文章

【.Net基础拾遗】匿名方法中的捕捉变量(探讨文)

最近在和朋友讨论的时候发现了一个很有意思的问题,就是捕捉变量,我现在下面把代码贴出来,大家可以先猜猜结果,然后我们在一起讨论为什么. 1 public class Test 2 { 3 private int k = 0; 4 private List<Action> dg1s = new List<Action>(), dg2s = new List<Action>(), dg3s = new List<Action>(); 5 public void f

匿名方法中的变量

前面一篇文章看到了C# 2.0中通过匿名方法来简化委托,下面来看看匿名方法中的变量. 闭包和不同的变量类型 闭包的基本概念是:一个函数除了能够通过提供给它的参数与环境交互之外,还能同环境进行更大程度的互动.对于C# 2.0中出现的匿名方法的闭包表现为,匿名方法能使用在声明该匿名方法的方法内部定义的局部变量. 在进一步了解闭包之前,我们先看看下面两个术语: 外部变量(outer variable):是指其作用域(scope)包括一个匿名方法的局部变量或参数(ref和out参数除外) 被捕捉的外部变

深入研究Block捕获外部变量和__block实现原理

Blocks是C语言的扩充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了这个新功能“Blocks”.从那开始,Block就出现在iOS和Mac系统各个API中,并被大家广泛使用.一句话来形容Blocks,带有自动变量(局部变量)的匿名函数. Block在OC中的实现如下: struct Block_layout { void *isa; int flags; int reserved; void (*invoke)(void *, ...); struct Bl

CoffeeScript中的外部变量与局部变量的屏蔽

刚接触CoffeeScript时,一直不清楚它存在的意义,搜索过部分资料,可以总结为两点:①语法糖,减少代码量增加可读性②增强js代码的合法性,编译之后的js代码跟手动写的相比基本没语法错误. 其实自我感觉代码量确实减少了,但是也并不是很可观,语法糖确实使用起来很方便,而语法错误这一点,个人感觉只要是对js有一定了解的人不一定会比他差,差也差不太多,个人感觉. 说一下在使用过程中遇到的比较头疼的一点,就是外部变量与局部变量的屏蔽机制. 如下代码: a = (callback) -> setTim

ros订阅函数的多线程使用方法(C++: 外部变量控制跳出for循环)

最初是想实现接收到某个some_topic然后解析内容,若是内容为指令action,action函数进入for循环,若是再接收到some_topic,里面指令为stop则stop=true停止正在进行的action,跳出for循环(想用外部变量控制for循环的结束). 类似: ros::NodeHandle n; ros::Subscriber sub = nh.subscribe(."some_topic",actionCallback..); . . . void actionCa

CI控制器中设置在其它方法中可用的变量

开发过程中,某些变量可能需要被控制器中的其它方法所调用,这个变量改怎么设置呢? 其实可以用ci的$this->load->vars($array);和$this->load->get_var($key);来实现. 数组可以在构造函数中设置,在方法中可以用get_var($key)获取value. class User extends CI_Controller{ public function __construct() { parent::__construct(); $arr

不能用private修饰方法中定义的变量

在敲代码时发现了一个自己之前没有注意到点:(确切来说是没有认真理解权限修饰符)在方法中定义变量时,不能加权限修饰符原因如下: 原文地址:https://blog.51cto.com/14234228/2468546

5.5 匿名方法中的捕获变量

class Program { static void Main(string[] args) { MethodInvoker m = CreateInvoker(); m(); m(); Console.ReadKey(); } static MethodInvoker CreateInvoker() { int count = 5; MethodInvoker ret = delegate { Console.WriteLine(count); count++; }; ret(); retu

Python:字符串中引用外部变量的3种方法

方法一: 1 username=input('username:') 2 age=input('age:') 3 job=input('job:') 4 salary=input('salary') 5 6 info1=''' 7 -----------------------info of %s---------------------------- 8 Name:%s 9 Age:%s 10 Job:%s 11 Salary:%s 12 ''' %(username,username,age