Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C语言中的委托问题#_C#_Delegates_Closures - Fatal编程技术网

C# C语言中的委托问题#

C# C语言中的委托问题#,c#,delegates,closures,C#,Delegates,Closures,在下面的程序中,DummyMethod始终打印5。但是如果我们使用注释代码,我们会得到不同的值(即1、2、3、4)。谁能解释一下为什么会这样 delegate int Methodx(object obj); static int DummyMethod(int i) { Console.WriteLine("In DummyMethod method i = " + i); return i +

在下面的程序中,DummyMethod始终打印5。但是如果我们使用注释代码,我们会得到不同的值(即1、2、3、4)。谁能解释一下为什么会这样

        delegate int Methodx(object obj);

        static int DummyMethod(int i)
        {
            Console.WriteLine("In DummyMethod method i = " + i);
            return i + 10;
        }

        static void Main(string[] args)
        {    
            List<Methodx> methods = new List<Methodx>();

            for (int i = 0; i < 5; ++i)
            {
                methods.Add(delegate(object obj) { return DummyMethod(i); });
            }

            //methods.Add(delegate(object obj) { return DummyMethod(1); });
            //methods.Add(delegate(object obj) { return DummyMethod(2); });
            //methods.Add(delegate(object obj) { return DummyMethod(3); });
            //methods.Add(delegate(object obj) { return DummyMethod(4); });

            foreach (var method in methods)
            {
                int c = method(null);
                Console.WriteLine("In main method c = " + c);
            }
        }
delegate int Methodx(对象对象对象);
静态int-dummy方法(int-i)
{
Console.WriteLine(“在DummyMethod方法i=“+i”);
返回i+10;
}
静态void Main(字符串[]参数)
{    
列表方法=新列表();
对于(int i=0;i<5;++i)
{
Add(委托(objectobj){return DummyMethod(i);});
}
//Add(委托(对象obj){return DummyMethod(1);});
//Add(委托(objectobj){return DummyMethod(2);});
//Add(委托(objectobj){return DummyMethod(3);});
//Add(委托(objectobj){return DummyMethod(4);});
foreach(方法中的var方法)
{
int c=方法(空);
Console.WriteLine(“主方法c=“+c”);
}
}
另外,如果使用以下代码,我将得到所需的结果

        for (int i = 0; i < 5; ++i)
        {
            int j = i;
            methods.Add(delegate(object obj) { return DummyMethod(j); });
        } 
for(int i=0;i<5;++i)
{
int j=i;
Add(委托(objectobj){return DummyMethod(j);});
} 

问题在于,在每个委托中都捕获了相同的变量
i
,在循环结束时,该变量的值仅为5

相反,您希望每个委托捕获不同的变量,这意味着在循环中声明一个新变量:

for (int i = 0; i < 5; ++i)
{
    int localCopy = i;
    methods.Add(delegate(object obj) { return DummyMethod(localCopy); });
}
for(int i=0;i<5;++i)
{
int localCopy=i;
Add(委托(对象obj){return DummyMethod(localCopy);});
}

这是一个非常常见的“问题”-您可以在中阅读更多关于捕获的变量和闭包的信息。

本文可能会帮助您了解发生了什么(即闭包是什么):

我认为这是因为变量
i
被放入堆(它是一个捕获的变量)


查看。

如果查看生成的代码(使用Reflector),您可以看到差异:

private static void Method2()
{
    List<Methodx> list = new List<Methodx>();
    Methodx item = null;
    <>c__DisplayClassa classa = new <>c__DisplayClassa();
    classa.i = 0;
    while (classa.i < 5)
    {
        if (item == null)
        {
            item = new Methodx(classa.<Method2>b__8);
        }
        list.Add(item);
        classa.i++;
    }
    foreach (Methodx methodx2 in list)
    {
        Console.WriteLine("In main method c = " + methodx2(null));
    }
}
private静态无效方法2()
{
列表=新列表();
Methodx item=null;
c_uuDisplayClassA classa=新的c_uDisplayClassA();
类别a.i=0;
而(A类i<5)
{
如果(项==null)
{
项目=新方法X(A.b类8);
}
列表。添加(项目);
classa.i++;
}
foreach(列表中的Methodx methodx2)
{
Console.WriteLine(“主方法c=“+methodx2(null));
}
}
当您使用初始代码时,它会在后台创建一个临时类,该类包含对“i”变量的引用,因此根据Jon的回答,您只能看到该变量的最终值

private sealed class <>c__DisplayClassa
{
    // Fields
    public int i;

    // Methods
    public <>c__DisplayClassa();
    public int <Method2>b__8(object obj);
}
专用密封类c\uu显示ClassA
{
//田地
公共国际一级;
//方法
公共c__DisplayClassa();
公共int b___8(对象obj);
}

我真的建议您查看中的代码,看看发生了什么,这就是我如何理解捕获的变量。确保您在选项菜单中将代码优化设置为“.NET 1.0”,否则它将隐藏所有的幕后内容。

Jon,试图让我了解为什么会发生这种情况。我把“I”看作是一种价值类型,认为“它必须作为一个副本传递”,所以我看不出它是如何具有类似引用的行为的。。。你有一个总结/一行字来告诉我正确的方向吗?看看最后的链接。让你头脑清醒的是,捕获的不是变量的值,而是变量本身。想想看:这就像有一个内联事件在方法的那个位置被调用,因此可以访问所有变量和状态,只有在调用未创建的方法时才能获得变量和状态。因此,您只是在调用方法时访问i,而不是在创建匿名方法时访问i。@Neil我在下面的回答中添加了“幕后”代码。这就是帮助我理解这一切的原因。我认为“捕获变量”是一个更有用的术语——确切地说,因为捕获的是变量而不是它的值。@Jon:听起来很合理,我倾向于这个问题。这种行为让人觉得“危险”。我敢打赌,随着C#越来越倾向于以面向委托的方式封装行为,它将越来越频繁地出现在那些难以调试的问题中。这就像是允许switch子句向下级联而不必强制“中断”的循环等价物clause@Neil当前位置我同意这是一个热门话题。当它与“foreach”一起出现时更令人困惑,以至于C#团队正在考虑改变这种情况下的行为。(很难想象foreach行为是理想的情况;for循环的情况更容易理解,因为很明显变量只声明了一次。)的可能重复