是这个对象
我回答了关于在C#编译器(如果重要的时候,4.0)遇到一些非常好奇的代码的情况下,关闭(合法地)延长对象生命期的可能性的问题。
我能找到的最短的repro如下:
结果:编译器创建一个闭包对象,该闭包对象引用创建lambda的对象,当它没有理由时 - 委托的“内部”目标是静态方法,并且lambda创建对象的实例成员不需要当代表执行时,(并没有)触及。 实际上,编译器的行为就像程序员没有理由捕获this
一样。
class Foo
{
private Action _field;
public void InstanceMethod()
{
var capturedVariable = Math.Pow(42, 1);
_field = () => StaticMethod(capturedVariable);
}
private static void StaticMethod(double arg) { }
}
从发布版本生成的代码(反编译为'简单'C#)看起来像这样:
public void InstanceMethod()
{
<>c__DisplayClass1 CS$<>8__locals2 = new <>c__DisplayClass1();
CS$<>8__locals2.<>4__this = this; // What's this doing here?
CS$<>8__locals2.capturedVariable = Math.Pow(42.0, 1.0);
this._field = new Action(CS$<>8__locals2.<InstanceMethod>b__0);
}
[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
// Fields
public Foo <>4__this; // Never read, only written to.
public double capturedVariable;
// Methods
public void <InstanceMethod>b__0()
{
Foo.StaticMethod(this.capturedVariable);
}
}
注意到<>4__this
这个闭包对象的<>4__this
字段被填充了一个对象引用,但永远不会被读取(没有理由)。
那么这里发生了什么? 语言规范是否允许? 这是一个编译器bug /奇怪还是有一个很好的理由(我明显缺少)的闭包引用该对象? 这让我感到焦虑,因为这看起来像一个封闭开发程序员(像我一样)不知不觉地将奇怪的内存泄漏(想象如果代理被用作事件处理程序)引入程序。
这确实看起来像一个错误。 感谢您的关注。 我会研究它。 它可能已被发现并修复。
这似乎是一个错误或不必要的:
我以IL语言运行你的例子:
.method public hidebysig
instance void InstanceMethod () cil managed
{
// Method begins at RVA 0x2074
// Code size 63 (0x3f)
.maxstack 4
.locals init (
[0] class ConsoleApplication1.Program/Foo/'<>c__DisplayClass1' 'CS$<>8__locals2'
)
IL_0000: newobj instance void ConsoleApplication1.Program/Foo/'<>c__DisplayClass1'::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldarg.0
IL_0008: stfld class ConsoleApplication1.Program/Foo ConsoleApplication1.Program/Foo/'<>c__DisplayClass1'::'<>4__this' //Make ref to this
IL_000d: nop
IL_000e: ldloc.0
IL_000f: ldc.r8 42
IL_0018: ldc.r8 1
IL_0021: call float64 [mscorlib]System.Math::Pow(float64, float64)
IL_0026: stfld float64 ConsoleApplication1.Program/Foo/'<>c__DisplayClass1'::capturedVariable
IL_002b: ldarg.0
IL_002c: ldloc.0
IL_002d: ldftn instance void ConsoleApplication1.Program/Foo/'<>c__DisplayClass1'::'<InstanceMethod>b__0'()
IL_0033: newobj instance void [mscorlib]System.Action::.ctor(object, native int)
IL_0038: stfld class [mscorlib]System.Action ConsoleApplication1.Program/Foo::_field
IL_003d: nop
IL_003e: ret
} // end of method Foo::InstanceMethod
例2:
class Program
{
static void Main(string[] args)
{
}
class Foo
{
private Action _field;
public void InstanceMethod()
{
var capturedVariable = Math.Pow(42, 1);
_field = () => Foo2.StaticMethod(capturedVariable); //Foo2
}
private static void StaticMethod(double arg) { }
}
class Foo2
{
internal static void StaticMethod(double arg) { }
}
}
在CL:(注意!!现在这个参考文件已经没有了!)
public hidebysig
instance void InstanceMethod () cil managed
{
// Method begins at RVA 0x2074
// Code size 56 (0x38)
.maxstack 4
.locals init (
[0] class ConsoleApplication1.Program/Foo/'<>c__DisplayClass1' 'CS$<>8__locals2'
)
IL_0000: newobj instance void ConsoleApplication1.Program/Foo/'<>c__DisplayClass1'::.ctor()
IL_0005: stloc.0
IL_0006: nop //No this pointer
IL_0007: ldloc.0
IL_0008: ldc.r8 42
IL_0011: ldc.r8 1
IL_001a: call float64 [mscorlib]System.Math::Pow(float64, float64)
IL_001f: stfld float64 ConsoleApplication1.Program/Foo/'<>c__DisplayClass1'::capturedVariable
IL_0024: ldarg.0 //No This ref
IL_0025: ldloc.0
IL_0026: ldftn instance void ConsoleApplication1.Program/Foo/'<>c__DisplayClass1'::'<InstanceMethod>b__0'()
IL_002c: newobj instance void [mscorlib]System.Action::.ctor(object, native int)
IL_0031: stfld class [mscorlib]System.Action ConsoleApplication1.Program/Foo::_field
IL_0036: nop
IL_0037: ret
}
例3:
class Program
{
static void Main(string[] args)
{
}
static void Test(double arg)
{
}
class Foo
{
private Action _field;
public void InstanceMethod()
{
var capturedVariable = Math.Pow(42, 1);
_field = () => Test(capturedVariable);
}
private static void StaticMethod(double arg) { }
}
}
在IL:(这个指针回来了)
IL_0006: ldloc.0
IL_0007: ldarg.0
IL_0008: stfld class ConsoleApplication1.Program/Foo ConsoleApplication1.Program/Foo/'<>c__DisplayClass1'::'<>4__this' //Back again.
在所有三种情况下,method-b__0() - 看起来都一样:
instance void '<InstanceMethod>b__0' () cil managed
{
// Method begins at RVA 0x2066
// Code size 13 (0xd)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld float64 ConsoleApplication1.Program/Foo/'<>c__DisplayClass1'::capturedVariable
IL_0006: call void ConsoleApplication1.Program/Foo::StaticMethod(float64) //Your example
IL_0006: call void ConsoleApplication1.Program/Foo2::StaticMethod(float64)//Example 2
IL_0006: call void ConsoleApplication1.Program::Test(float64) //Example 3
IL_000b: nop
IL_000c: ret
}
在所有3种情况下,都提到了静态方法,所以它更加奇怪。 所以在这个小问题分析之后,我会说它是一个bug /不好。 !
链接地址: http://www.djcxy.com/p/51509.html上一篇: Is this object
下一篇: Is there a difference between (function() {...}()); and (function() {...})();?