为什么这段代码返回109?

时间:2012-02-12 01:49:03

标签: c# func lambda

有人能告诉我它是如何运作的吗?我会很感激。 Dunno如何调试这个。

using System;

    class Prg
    {
        private static Func<double, Func<double, double>> Add(int c)
        {
            return x => y => x + y++ + (c *= 2);
        }

        public static void Main(string[] args)
        {
            int a = 1;
            int b = 100;
            var F = Add(2);
            var G = F(a);
            G(b);
            Console.WriteLine(G(b));
        }
    }
编辑:如果你想参加我们的C#考试,我还有另一个。这是代码。

delegate int F(); 
class Prg { int a = 10; 
  public F Adder(int x) { 
    int i = x; 
    return delegate { 
      return a += i++; }; 
  } 
  static void Main() { 
    Prg p = new Prg(); 
    F f = p.Adder(5); 
    p.Adder(10); 
    f(); 
    System.Console.Write(f()); 
}  } 

2 个答案:

答案 0 :(得分:3)

我将从:不要写这样的代码。

如果你真的想知道发生了什么:

  1. 在行var F = Add(2)中,方法Add()创建并返回一个lambda表达式,其中c == 2。这里重要的是c被lambda捕获(您可以阅读有关在msdn上捕获变量的内容。
  2. 在行var G = F(x)中,您只是使用参数a = 1调用您的函数,结果会得到另一个函数,确切地说double -> double
  3. G(b)行中,您正在调用您的函数,正是这个函数:x + y++ + (c *= 2);现在:
    • x等于1
    • y是您的参数,它等于100
    • c等于2,但它被捕获,因此它实际上是对某些已分配字段的引用
    • 这个表达式的结果是105(100 ++返回100,2 * = 2返回4),所以得到1 + 100 + 4 = 105.但是,更重要的是,变量c,这是捕获现在等于4. y只是一个参数,因此它没有改变。
  4. 在行Console....中,您再次调用您的函数。这一次,参数再次等于100,因此结果会相同,但您捕获的变量c现在等于4,因此您收到的结果为1 + (100+) + (4 *= 2) -> 1 + 100 + 8 -> 109
  5. 这是一个简短的例子,可能会对那里发生的事情有所启发:

    class Prg
    {
        public static void Main(string[] args)
        {
            int captured = 5;
            int param = 3;
    
            var func = new Func<int, int>(x => x * captured);
    
            Console.WriteLine(func(param));
            captured = 6;
            Console.WriteLine(func(param));
    
        }
    }
    

答案 1 :(得分:2)

这部分执行两次:

c *= 2

第一次打电话给G(b)。第二次打印到控制台时。

一次执行实际上计算:

a + b++ + (c *= 2)

但是由于c在每次执行时都会乘以2(并返回到c),因此得到109而不是105. 变量c被引用为函数范围内的一个精确内存位置Add ,实际上用作Func委托(并且Func的实例始终保持相同),这就是为什么这与使用函数进行一些嵌套调用(其中只有按值传递)的原因不同函数,返回值,函数范围关闭,永远不会再使用相同的上下文访问。)