C# Is action.BeginInvoke(action.EndInvoke,null) a good idea?

前端 未结 2 1460
说谎
说谎 2021-02-13 15:31

If I want to do a \"fire and forget\" of some code, but still want to ensure that my memory is cleaned up (per Why does asynchronous delegate method require calling EndInvoke?),

相关标签:
2条回答
  • 2021-02-13 15:48

    Using a method group conversion instead of a delegate is fine, the EndInvoke will still be called in on your Action. There is nothing else to be done, since this is a fire and forget call.

    Unfortunately, it's somewhat hard to directly irrefutably prove that EndInvoke is called, since Action is a delegate and we can't just add a breakpoint on some class in the BCL.

    This code will (periodically) inspect some private field of the IAsyncResult that is returned by BeginInvoke, which seems to keep track of whether or not EndInvoke has been called yet:

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

    I've double checked using SOS that there aren't any managed memory leaks. I've also tried several other proofs, but they were more circumstantial than this one, I think.

    Some interesting I discovered during my investigation: the myAction.BeginInvoke call will show up on profilers using instrumentation, but myAction.EndInvoke does not.

    0 讨论(0)
  • 2021-02-13 15:53

    Nowdays it could be done like

    BeginInvoke((Action)(async () =>
    {
        // Show child form
        var f = new MyForm();
        f.ShowDialog();
        // Update parent/current
        await UpdateData();
    }));
    
    0 讨论(0)
提交回复
热议问题