当传递到委托整数引用类型处理 [英] Integer handled as reference type when passed into a delegate

查看:110
本文介绍了当传递到委托整数引用类型处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在本周出席TechDays 2013在荷兰,我得到了一个有趣的小测验的问题提出的。现在的问题是:什么是下面的程序的输出。这里是代码的样子

 类节目
{
委托无效作家();

静态无效的主要(字串[] args)
{
变种作家=新的List<&作家GT;();
的for(int i = 0;我小于10;我++)
{
writers.Add(代表{Console.WriteLine(一);});
}

的foreach(在作家作家作家)
{
作家();
}
}
}



显然,答案我给错了。我argumentend,因为int是一个值类型,()被复制传递到的实际值Console.WriteLine,所以输出将是0到9。然而 I 作为在这种情况下引用类型处理。正确的答案是,它会显示十倍10.任何人能解释为何以及如何?


解决方案

我argumentend,因为int是一个值类型,传递到Console.WriteLine()被复制的实际值




这是完全正确。 当你调用的WriteLine 的值将被复制



所以,当你调用的WriteLine ?这不是在循环。你不是在时间写在这一点上任何东西,你只是创建一个代表。



这不是等到什么时候你调用委托的foreach 循环,这是在那个时候,在变量的值 I 复制到堆栈调用的WriteLine



那么,什么是 I 的foreach 循环?这是10,为的foreach 每次循环。



所以,现在你问,那么怎么样 I foreach循环过程中什么,是不是超出范围。哦,不,不是这样的。这是什么正在证明是一个封闭。当一个匿名方法引用变量的作用域需要持续,只要该匿名方法,这可能是任何时间段的一个变量。如果没有什么特别的完成所有读取变量会包含随机垃圾无论发生在被卡在该位置在内存中。C#积极确保这种情况不会发生。



那么它有什么功能?它创建一个封闭一流;它是将包含一个数字代表的是封闭高于一切领域的一类。换句话说,代码将被重构看起来是这样的:

 公共类ClosureClass 
{
公众诠释我;

公共无效DoStuff()
{
Console.WriteLine(一世);
}
}

类节目
{
委托无效作家();

静态无效的主要(字串[] args)
{
变种作家=新的List<&作家GT;();
ClosureClass关闭=新ClosureClass();
为(closure.i = 0; closure.i小于10; closure.i ++)
{
writers.Add(closure.DoStuff);
}

的foreach(在作家作家作家)
{
作家();
}
}
}

现在我们都有一个名字我们的匿名方法(所有的匿名方法给出了由编译器的名称),我们可以确保变量将生活,只要引用匿名函数生活中的代表。



看着这个重构,我希望它清楚为什么结果是 10 印刷10次。


I was attending the TechDays 2013 in the Netherlands this week and I got an interesting quiz question presented. The question was: What is the output of the following program. Here is what the code looks like.

class Program
{
    delegate void Writer();

    static void Main(string[] args)
    {
        var writers = new List<Writer>();
        for (int i = 0; i < 10; i++)
        {
            writers.Add(delegate { Console.WriteLine(i); });
        }

        foreach (Writer writer in writers)
        {
            writer();
        }
    }
}

Obviously, the answer I gave was wrong. I argumentend, because int is a value type, the actual value that is passed into Console.WriteLine() gets copied, so the output would be 0...9. However i is handled as a reference type in this situation. The correct answer is that it will display ten times 10. Can anyone explain why and how?

解决方案

I argumentend, because int is a value type, the actual value that is passed into Console.WriteLine() gets copied

That is exactly correct. When you call WriteLine the value will be copied.

So, when are you calling WriteLine? It's not in the for loop. You're not writing anything at that point in time, you're just creating a delegate.

It's not until the foreach loop when you invoke the delegate, it's at that time that the value in the variable i is copied to the stack for the call to WriteLine.

So, what's the value of i during the foreach loop? It's 10, for each iteration of the foreach loop.

So now you're asking, "well how is i anything during the foreach loop, isn't it out of scope. Well, no, it's not. What this is demonstrating is a "closure". When an anonymous method reference a variable that variable's scope needs to last for as long as that anonymous method, which could be for any period of time. If nothing special is done at all reading the variable would be random garbage containing whatever happened to be stuck in that location in memory. C# actively makes sure that situation can't happen.

So what does it do? It creates a closure class; it's a class that will contain a number of fields representing everything that is closed over. In other words, the code will be refactored to look something like this:

public class ClosureClass
{
    public int i;

    public void DoStuff()
    {
        Console.WriteLine(i);
    }
}

class Program
{
    delegate void Writer();

    static void Main(string[] args)
    {
        var writers = new List<Writer>();
        ClosureClass closure = new ClosureClass();
        for (closure.i = 0; closure.i < 10; closure.i++)
        {
            writers.Add(closure.DoStuff);
        }

        foreach (Writer writer in writers)
        {
            writer();
        }
    }
}

Now we both have a name for our anonymous method (all anonymous methods are given a name by the compiler) and we can ensure that the variable will live for as long as the delegate that refers to the anonymous function lives.

Looking at this refactor, I hope it's clear why the result is that 10 is printed 10 times.

这篇关于当传递到委托整数引用类型处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆