共享一个类的离散匿名方法? [英] Discrete Anonymous methods sharing a class?

查看:13
本文介绍了共享一个类的离散匿名方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在玩 这里.我在 IL 中注意到,看起来两个匿名方法都在使用同一个生成的类,即使这意味着该类有一个额外的变量.

I was playing a bit with Eric Lippert's Ref<T> class from here. I noticed in the IL that it looked like both anonymous methods were using the same generated class, even though that meant the class had an extra variable.

虽然只使用一个新的类定义似乎有些合理,但让我觉得很奇怪的是只创建了一个 <>c__DisplayClass2 实例.这似乎意味着 Ref<T> 的两个实例都引用了相同的 <>c__DisplayClass2 这是否意味着 y 不能在 vart1 被收集之前被收集,这可能比 joik 返回之后发生的时间晚得多?毕竟,不能保证某些白痴不会编写一个函数(直接在 IL 中)通过 vart1joik 之后直接访问 y返回.也许这甚至可以通过反射而不是通过疯狂的 IL 来完成.

While using only one new class definition seems somewhat reasonable, it strikes me as very odd that only one instance of <>c__DisplayClass2 is created. This seems to imply that both instances of Ref<T> are referencing the same <>c__DisplayClass2 Doesn't that mean that y cannot be collected until vart1 is collected, which may happen much later than after joik returns? After all, there is no guarantee that some idiot won't write a function (directly in IL) which directly accesses y through vart1 aftrer joik returns. Maybe this could even be done with reflection instead of via crazy IL.

sealed class Ref<T>
{
    public delegate T Func<T>();
    private readonly Func<T> getter;
    public Ref(Func<T> getter)
    {
        this.getter = getter;
    }
    public T Value { get { return getter(); } }
}

static Ref<int> joik()
{
    int[] y = new int[50000];
    int x = 5;
    Ref<int> vart1 = new Ref<int>(delegate() { return x; });
    Ref<int[]> vart2 = new Ref<int[]>(delegate() { return y; });
    return vart1;
}

运行 IL DASM 确认 vart1vart2 都使用 <>__DisplayClass2,其中包含 x 和 y 的公共字段.joik 的 IL:

Running IL DASM confirmed that vart1 and vart2 both used <>__DisplayClass2, which contained a public field for x and for y. The IL of joik:

.method private hidebysig static class Program/Ref`1<int32> 
        joik() cil managed
{
  // Code size       72 (0x48)
  .maxstack  3
  .locals init ([0] class Program/Ref`1<int32> vart1,
           [1] class Program/Ref`1<int32[]> vart2,
           [2] class Program/'<>c__DisplayClass2' '<>8__locals3',
           [3] class Program/Ref`1<int32> CS$1$0000)
  IL_0000:  newobj     instance void Program/'<>c__DisplayClass2'::.ctor()
  IL_0005:  stloc.2
  IL_0006:  nop
  IL_0007:  ldloc.2
  IL_0008:  ldc.i4     0xc350
  IL_000d:  newarr     [mscorlib]System.Int32
  IL_0012:  stfld      int32[] Program/'<>c__DisplayClass2'::y
  IL_0017:  ldloc.2
  IL_0018:  ldc.i4.5
  IL_0019:  stfld      int32 Program/'<>c__DisplayClass2'::x
  IL_001e:  ldloc.2
  IL_001f:  ldftn      instance int32 Program/'<>c__DisplayClass2'::'<joik>b__0'()
  IL_0025:  newobj     instance void class Program/Ref`1/Func`1<int32,int32>::.ctor(object,
                                                                                    native int)
  IL_002a:  newobj     instance void class Program/Ref`1<int32>::.ctor(class Program/Ref`1/Func`1<!0,!0>)
  IL_002f:  stloc.0
  IL_0030:  ldloc.2
  IL_0031:  ldftn      instance int32[] Program/'<>c__DisplayClass2'::'<joik>b__1'()
  IL_0037:  newobj     instance void class Program/Ref`1/Func`1<int32[],int32[]>::.ctor(object,
                                                                                        native int)
  IL_003c:  newobj     instance void class Program/Ref`1<int32[]>::.ctor(class Program/Ref`1/Func`1<!0,!0>)
  IL_0041:  stloc.1
  IL_0042:  ldloc.0
  IL_0043:  stloc.3
  IL_0044:  br.s       IL_0046
  IL_0046:  ldloc.3
  IL_0047:  ret
} // end of method Program::joik

推荐答案

是的,匿名方法的 MS 实现有效地为每个范围级别创建一个隐藏类,它需要从中捕获变量,并捕获所有em> 该范围内的相关变量.我相信这样做是为了简单起见,但它确实会不必要地增加某些对象的生命周期.

Yes, the MS implementation of anonymous methods effectively creates one hidden class per level of scope that it needs to capture variables from, and captures all the relevant variables from that scope. I believe this is done for the sake of simplicity, but it can indeed increase the lifetime of some objects unnecessarily.

每个匿名方法捕获它实际感兴趣的变量会更优雅.但是,这可能会使生活相当更加复杂......如果一个匿名方法捕获 xy,一个捕获 x 和一个捕获 y,你需要三个类:一种用于捕获 x,一种用于捕获 y,一种用于组合两者(但 只有两个变量).棘手的一点是,对于任何单个变量的实例化,该变量都需要恰好位于一个位置,以便引用它的所有内容都看到相同的值,无论它发生什么变化.

It would be more elegant for each anonymous method to only capture the variables it was actually interested in. However, this could make life considerably more complicated... if one anonymous method captured x and y, one captured x and one captured y, you'd need three classes: one for capturing x, one for capturing y, and one for composing the two (but not just having two variables). The tricky bit is that for any single variable instantiation, that variable needs to live in exactly one place so that everything which refers to it sees the same value, whatever changes it.

这并没有以任何方式违反规范,但它可能被认为是不幸的 - 我不知道它是否真的被现实生活中的人咬伤了,但这肯定是可能的.

This doesn't violate the spec in any way, but it could be considered unfortunate - I don't know whether it's actually bitten people in real life, but it's certainly possible.

好消息是,如果 C# 团队决定改进这一点,他们应该能够以完全向后兼容的方式这样做,除非某些木偶依赖不必要地延长生命周期.

The good news is that if the C# team decide to improve this, they should be able to do so in an entirely backwardly compatible way, unless some muppets are relying on lifetimes being extended unnecessarily.

这篇关于共享一个类的离散匿名方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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