2013-04-12 3 views
11

Если я хочу сделать «огонь и забыть» какого-то кода, но все же хочу убедиться, что моя память очищена (за Why does asynchronous delegate method require calling EndInvoke?), достигнет ли следующая цель?C# Is action.BeginInvoke (action.EndInvoke, null) хорошая идея?

Action myAction =() => LongRunTime(); 
myAction.BeginInvoke(myAction.EndInvoke,null); 

Я осмотрелся, но не видел, чтобы этот шаблон использовался где угодно. Скорее, люди используют метод annonomoyus в качестве своего обратного вызова (например, The proper way to end a BeginInvoke?) или определяют фактический метод обратного вызова. Поскольку я не видел, чтобы кто-то еще это делал, это заставляет меня думать, что это либо не работает, либо плохой идеей.

Спасибо!

+1

Я не вижу проблем с использованием преобразования группы методов над выражением лямбда. – Thorarin

+1

Если вы можете добавить ответ так или иначе, если эта техника не вызовет утечку памяти, тогда это будет ответом, который я ищу. Благодаря! –

ответ

12

Использование преобразования группы методов вместо делегата в порядке, EndInvoke все равно будет вызываться на вашем Action. Больше ничего не поделаешь, так как это огонь и забудьте позвонить.

К сожалению, трудно прямо необоснованно доказать, что EndInvoke вызывается, поскольку Action является делегатом, и мы не можем просто добавить точку останова в некоторый класс в BCL.

Этот код (периодически) проверять некоторые частные поле IAsyncResult, возвращенного BeginInvoke, который, кажется, чтобы отслеживать, была ли EndInvoke была вызвана:

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; 
      } 
     } 
    } 
} 

Я проверил используя SOS, что нет утечек управляемой памяти. Я также попробовал несколько других доказательств, но они были более косвенными, чем эта, я думаю.

Некоторое интересное, которое я обнаружил в ходе моего расследования: вызов myAction.BeginInvoke будет отображаться на профилографах с использованием приборов, но myAction.EndInvoke нет.

+0

Нет никакого смысла в этом, что я вижу. Просто вызовите LongRunTime() непосредственно внутри задачи. –

+3

Задача была, помимо точки, но вот пример без задачи, если вы предпочитаете. – Thorarin

+0

+1 Спасибо Thorarin! Отличные подробности и исследования! –

Смежные вопросы