让我们检查以下场景(翻译事件):
public void HookSpecificButton(SpecificButton specificButton, EventHandler eh)
{
specificButton.SpecificClick += (o, e) => eh(o, EventArgs.Empty);
}
代码的重点是将事件从一种类型转换为另一种类型:我不关心specificButton
通过SpecificClick
传递的数据,我想要附加到此事件的常规EventHandler
我的问题如下。 eh
包含对某个对象的方法的引用。如果没有其他对该对象的引用,lambda是否足以让该对象保持活动状态?链是:
specificButton
保留了EventHandler<SpecificData>
的实例,该实例保持活动(lambda)
保持活动(?) EventHandler
的实例,保持最终的目标。
答案 0 :(得分:2)
对象将保持活跃状态。它仍然是根深蒂固的#34;因为从按钮到对象的对象引用链包含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
的{{1}}字段,以及一个EventHandler
和object
的方法。
所以我们有以下参考资料:
RoutedEventArgs
MyButton - &gt; Button
RoutedEventHandler
- &gt; RoutedEventHandler
<>c__DisplayClass1
- &gt; <>c__DisplayClass1
eh EventHandler
eh - &gt; EventHandler
(MyWindow
)这里是嵌套子类OnButtonClicked
的ILDasm输出:
MainWindow
当然,在我的示例中,无论如何,提供的事件处理程序都是root的,因为它位于 .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'
本身。但即使情况并非如此,也不会是GC&#39; d。
这意味着您可以获得实际需要的行为。但在许多应用程序中,它会导致内存泄漏。这就是编写代码以取消订阅事件或使用弱事件模式如此重要的原因。