對象將保持活着。它仍然是「紮根」的,因爲從按鈕到包含由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