Utilizzando un metodo di conversione di gruppo invece di un delegato va bene, il EndInvoke
sarà ancora chiamato a sul vostro Action
. Non c'è nient'altro da fare, dato che è un incendio e dimentica la chiamata.
Sfortunatamente, è un po 'difficile dimostrare direttamente che EndInvoke è chiamato, dal momento che Action
è un delegato e non possiamo semplicemente aggiungere un punto di interruzione su qualche classe nel BCL.
Questo codice (periodicamente) ispezionare qualche campo privato del IAsyncResult restituito da BeginInvoke
, che sembra tenere traccia di se o non EndInvoke
è stato ancora chiamato:
public partial class MainWindow : Window
{
private Timer _timer = new Timer(TimerCallback, null, 100, 100);
private static IAsyncResult _asyncResult;
public MainWindow()
{
InitializeComponent();
}
static void LongRunTime()
{
Thread.Sleep(1000);
}
void Window_Loaded(object sender, RoutedEventArgs args)
{
Action myAction =() => LongRunTime();
_asyncResult = myAction.BeginInvoke(myAction.EndInvoke, null);
}
static void TimerCallback(object obj)
{
if (_asyncResult != null)
{
bool called = ((dynamic)_asyncResult).EndInvokeCalled;
if (called)
{
// Will hit this breakpoint after LongRuntime has completed
Debugger.Break();
_asyncResult = null;
}
}
}
}
ho ricontrollato usando SOS che non ci sono perdite di memoria gestita. Ho anche provato diverse altre prove, ma erano più circostanziali di questo, credo.
Alcuni interessanti che ho scoperto durante la mia indagine: la chiamata myAction.BeginInvoke
verrà visualizzata sui profiler utilizzando la strumentazione, ma non lo è lo myAction.EndInvoke
.
Non vedo alcun problema con l'utilizzo di una conversione del gruppo metodo su un'espressione lambda. – Thorarin
Se è possibile aggiungere una risposta in un modo o nell'altro se questa tecnica non causa una perdita di memoria, quella sarebbe la risposta che sto cercando. Grazie! –