对象将保持活着。它仍然是“扎根”的,因为从按钮到包含由eh
所指的方法的对象引用了一系列对象。
根据Simon Whitehead对您的问题的评论,编译器翻译此代码很有趣。借此扩大你的代码:
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
HookSpecificButton(this.MyButton, this.OnButtonClicked);
}
private void OnButtonClicked(object sender, EventArgs e)
{
}
public static void HookSpecificButton(Button specificButton, EventHandler eh)
{
specificButton.Click += (o, e) => eh(o, EventArgs.Empty);
}
}
其中Click
事件处理程序被钩线实际上是简写:
specificButton.Click += new RoutedEventHandler((o, e) => eh(o, EventArgs.Empty));
这阐明你的确创造了RoutedEventHandler
委托对象。委托(用于非静态方法调用)包装对目标对象的引用以及对该对象的实例方法的引用。
我们可以使用ILDasm检查lambda表达式会发生什么。我在MainWindow
内看到一个嵌套的类,名为<>c__DisplayClass1
。这个类别有一个类型的字段eh
,以及一个需要object
和RoutedEventArgs
的方法。
因此,我们有以下参考资料:
Button
myButton的 - >RoutedEventHandler
RoutedEventHandler
- ><>c__DisplayClass1
<>c__DisplayClass1
- >EventHandler
诶
EventHandler
诶 - >MyWindow
(OnButtonClicked
)
下面是嵌套子类的MainWindow
的反汇编输出:
.class auto ansi sealed nested private beforefieldinit '<>c__DisplayClass1'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (01 00 00 00)
.field public class [mscorlib]System.EventHandler eh
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method '<>c__DisplayClass1'::.ctor
.method public hidebysig instance void
'<HookSpecificButton>b__0'(object o,
class [PresentationCore]System.Windows.RoutedEventArgs e) cil managed
{
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.EventHandler ObjectLifetimeTest.MainWindow/'<>c__DisplayClass1'::eh
IL_0006: ldarg.1
IL_0007: ldsfld class [mscorlib]System.EventArgs [mscorlib]System.EventArgs::Empty
IL_000c: callvirt instance void [mscorlib]System.EventHandler::Invoke(object,
class [mscorlib]System.EventArgs)
IL_0011: ret
} // end of method '<>c__DisplayClass1'::'<HookSpecificButton>b__0'
} // end of class '<>c__DisplayClass1'
当然,在我的例子中所提供的事件处理程序反正扎根,因为它是在Window
本身。但即使情况并非如此,它也不会被GC'd。
这意味着你会得到你想要的行为。但在许多应用程序中,这是一个导致内存泄漏的问题。这就是编写代码以取消订阅事件或使用弱事件模式非常重要的原因。
是的,就够了。 GC不会收集仍在使用的物体 – knittl
在此情况下, “呃”包含对某个对象方法的引用 - 你能详细说明一下吗?它捕获函数调用eh。 –
'eh'是一个委托 - 方法引用的容器。但是每个方法都必须在某个上下文中调用,所以委托包含对方法*和*的引用,这些方法是该方法的所有者。 – Spook