当前位置: 首页 > 面试题库 >

NET中如何实现匿名方法中的捕获值

越涵衍
2023-03-14
问题内容

我对实际的.NET实现及其背后的决定感到好奇。

例如,在Java中,匿名类中使用的所有捕获值都必须是最终值。NET中似乎已删除了此要求。

此外,与参考类型相反,值类型的捕获值的实现方式是否有所不同?

谢谢


问题答案:

找出实现方式的最简单方法就是尝试一下。编写一些代码,使用捕获的变量,对其进行编译,然后在Reflector中对其进行查看。请注意,捕获的是 变量 ,而不是 value
。这是Java和C#在此方面的最大区别之一。

基本思想是,包含至少一个捕获变量的范围的每个级别都会导致一个新类,其中包含已捕获变量的字段。如果存在多个级别,则内部作用域还具有用于下一个作用域的字段,依此类推。堆栈上真正的局部变量最终将引用自动生成类的实例。

这是一个例子:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<Action> actions = new List<Action>();

        for (int i=0; i < 5; i++)
        {
            int copyOfI = i;

            for (int j=0; j < 5; j++)
            {
                int copyOfJ = j;

                actions.Add(delegate
                {
                    Console.WriteLine("{0} {1}", copyOfI, copyOfJ);
                });
            }
        }

        foreach (Action action in actions)
        {
            action();
        }        
    }
}

(如果不学习课程,您将得到不同的结果-实验!)这将编译为如下代码:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<Action> actions = new List<Action>();

        for (int i=0; i < 5; i++)
        {
            OuterScope outer = new OuterScope();
            outer.copyOfI = i;

            for (int j=0; j < 5; j++)
            {
                InnerScope inner = new InnerScope();
                inner.outer = outer;
                inner.copyOfJ = j;

                actions.Add(inner.Action);
            }
        }

        foreach (Action action in actions)
        {
            action();
        }        
    }

    class OuterScope
    {
        public int copyOfI;
    }

    class InnerScope
    {
        public int copyOfJ;
        public OuterScope outer;

        public void Action()
        {
            Console.WriteLine("{0} {1}", outer.copyOfI, copyOfJ);
        }
    }
}

对捕获变量的每个引用最终都要经过所生成类的实例,因此它不仅仅是一次性复制。(好的,在这种情况下,代码中没有其他任何东西使用捕获的变量,但是您可以很容易地想象得到。)请注意,对于外循环的任何一次迭代,五个
新实例都共享一个的实例OuterScope。您可能想尝试在委托中使用额外的代码,以查看其如何影响事物-如果
委托更改copyofI,则将在下一个委托中看到更改;不会看到对的更改,copyOfJ因为下一个委托将使用的单独实例InnerScope



 类似资料:
  • 本文向大家介绍Java中匿名类的两种实现方式,包括了Java中匿名类的两种实现方式的使用技巧和注意事项,需要的朋友参考一下 使用匿名内部类课使代码更加简洁、紧凑,模块化程度更高。内部类能够访问外部内的一切成员变量和方法,包括私有的,而实现接口或继承类做不到。然而这个不是我说的重点,我说的很简单,就是匿名内部类的两种实现方式:第一种,继承一个类,重写其方法;第二种,实现一个接口(可以是多个),实现其

  • Java7编译器是如何处理多捕获块的?一个简单的实现是生成字节码,就好像存在多个catch块一样。然而,我从多个来源得到的信息表明,情况并非如此--处理多个异常类型的catch块在编译期间不会产生重复的字节码。 那么,它是如何工作的呢?是否有一个新的字节码指令告诉JVM关于多捕获块?

  • 本文向大家介绍ASP.NET中实现获取调用方法名,包括了ASP.NET中实现获取调用方法名的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了ASP.NET中实现获取调用方法名的技巧。分享给大家供大家参考。具体实现方法如下: 在写记录日志功能时,需要记录日志调用方所在的模块名、命名空间名、类名以及方法名,想到使用的是反射(涉及到反射请注意性能),但具体是哪一块儿还不了解,于是搜索,整理如下:

  • 问题 你用lambda定义了一个匿名函数,并想在定义时捕获到某些变量的值。 解决方案 先看下下面代码的效果: >>> x = 10 >>> a = lambda y: x + y >>> x = 20 >>> b = lambda y: x + y >>> 现在我问你,a(10)和b(10)返回的结果是什么?如果你认为结果是20和30,那么你就错了: >>> a(10) 30 >>> b(10)

  • Try-catch旨在帮助处理异常。这意味着它将帮助我们的系统更加健壮:尝试从一个意外事件中恢复。 我们怀疑在执行and指令(发送消息)时可能会发生一些事情,因此它被封闭在try中。如果发生了几乎意想不到的事情,我们可以做一些事情:我们编写catch。我不认为我们打电话只是为了记录异常。我认为catch块是为了给我们从错误中恢复的机会。 现在,假设我们可以从错误中恢复,因为我们可以修复错误。再试一

  • null 我的例外是没有被抓到。我做错了什么?