Discrete Anonymous methods sharing a class?(共享一个类的离散匿名方法?)
问题描述
我在玩 Ref<T> 课程-reference-to-a-class-field-in-c/2982037#2982037">这里.我在 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 中)通过 vart1
在 joik
之后直接访问 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 确认 vart1
和 vart2
都使用 <>__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.
每个匿名方法只捕获它实际感兴趣的变量会更优雅.但是,这可能会使生活相当更加复杂......如果一个匿名方法捕获 x
和 y
,一个捕获 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.
这篇关于共享一个类的离散匿名方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:共享一个类的离散匿名方法?
基础教程推荐
- SSE 浮点算术是否可重现? 2022-01-01
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30
- MS Visual Studio .NET 的替代品 2022-01-01
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01
- 将 XML 转换为通用列表 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01
- 如何激活MC67中的红灯 2022-01-01
- c# Math.Sqrt 实现 2022-01-01
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01