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

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

问题描述

我玩埃里克利珀的参考℃的位; T&GT; 类从<一个href=\"http://stackoverflow.com/questions/2980463/how-do-i-assign-by-reference-to-a-class-field-in-c/2982037#2982037\">here.我在IL注意到,它看起来像匿名方法使用相同的生成的类人,即使那意味着类有一个额外的变量。

虽然只使用一个新的类定义似乎有些合理的,这令我很奇怪,只有一个&LT实例;&GT; c__DisplayClass2 创建。这似乎在暗示,的两个实例参考&LT; T&GT; 引用的是同一个&LT;&GT; c__DisplayClass2 不这意味着无法收集到 vart1 的收集,这可能远远晚于后 joik 的回报?毕竟,没有哪个直接访问Ÿ保证一些白痴不会写一个函数(直接在伊利诺斯州) vart1 aftrer joik 的回报。也许这甚至可以与反思,而不是通过疯狂的IL来完成。

 密封类参考&LT; T&GT;
{
    公共委托ŧFunc键&LT; T&GT;();
    私人只读Func键&LT; T&GT;吸收剂;
    公共参考(Func键&LT; T&GT;吸气)
    {
        this.getter =吸收剂;
    }
    公众的T值{{返回吸气剂(); }}
}静态参考&LT; INT&GT; joik()
{
    INT [] Y =新INT [50000];
    INT X = 5;
    参考&LT; INT&GT; vart1 =新的参考&LT; INT&GT;(委托(){返回X;});
    参考&LT; INT [] GT; vart2 =新的参考&LT; INT []&GT;(委托(){返回Ÿ;});
    返回vart1;
}

运行IL DASM证实, vart1 vart2 都使用&LT;&GT; __ DisplayClass2 ,其中包含一个公共领域x和y的。 joik的IL:

 。方法私人hidebysig静态类节目/ Ref`1&LT;&INT32 GT;
        joik()CIL管理
{
  // code尺寸72(0x48)
  .maxstack 3
  .locals的init([0]类节目/ Ref`1&LT;&INT32 GT; vart1,
           [1]类节目/ Ref`1&LT; INT32 []&GT; vart2,
           [2]类节目/'&LT;&GT; c__DisplayClass2''&LT;&GT; 8__locals3',
           [3]类节目/ Ref`1&LT;&INT32 GT; CS $ 1 $ 0000)
  IL_0000:newobj实例无效程序/'&LT;&GT; c__DisplayClass2'::构造函数()。
  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 []程序/'&LT;&GT; c__DisplayClass2'::ÿ
  IL_0017:ldloc.2
  IL_0018:ldc.i4.5
  IL_0019:stfld INT32程序/'&LT;&GT; c__DisplayClass2':: X
  IL_001e:ldloc.2
  IL_001f:ldftn例如INT32程序/'&LT;&GT; c__DisplayClass2'::'&LT; joik&GT; b__0'()
  IL_0025:newobj实例无效类节目/ Ref`1 / Func`1&LT; INT32,INT32&GT; ::构造函数(对象,
                                                                                    原生INT)
  IL_002a:newobj实例无效类节目/ Ref`1&LT;&INT32 GT; ::构造函数(!类节目/ Ref`1 / Func`1℃下,0&GT;)
  IL_002f:stloc.0
  IL_0030:ldloc.2
  IL_0031:ldftn例如INT32 []程序/'&LT;&GT; c__DisplayClass2'::'&LT; joik&GT; b__1'()
  IL_0037:newobj实例无效类节目/ Ref`1 / Func`1&LT; INT32 [],INT32 []&GT; ::构造函数(对象,
                                                                                        原生INT)
  IL_003c:newobj实例无效类节目/ Ref`1&LT; INT32 []&GT; ::构造函数(!类节目/ Ref`1 / Func`1℃下,0&GT;)
  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
} //方法程序结束:: joik


解决方案

是的,匿名方法的MS实施有效地创建每范围级别一个隐藏的类,它需要捕捉变量和捕捉的所有从范围相关的变量。相信这是为了简单起见完成,但它确实可以增加一些对象的生存不必要地

这将是每个匿名方法的只有的捕捉它是真正感兴趣的变量。但是,这可能使生活的相当的更复杂更优雅......如果一位不愿透露姓名的方法捕获 X ,一是抓获 X 和一个捕捉,你需要三个类:一个用于捕获 X ,一个用于捕捉,一个用于合成两个(但的的仅仅有两个变量)。棘手的一点是,任何单变量实例,该变量需要住在只有一个地方,以便它指的是使一切都看到同样的价值,无论对其进行更改。

这并不违反任何方式的规范,但可以认为它是不幸的 - 我不知道是否实际上咬在现实生活中的人,但它肯定可以

好消息是,如果C#团队决定要改善这一点,他们应该能够在一个完全向后兼容的方​​式这样做,除非是一些布偶是的依赖的对寿命进行不必要的延长。

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.

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;
}

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

解决方案

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.

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.

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天全站免登陆