С# Является ли action.BeginInvoke(action.EndInvoke, null) хорошей идеей?

Если я хочу сделать "огонь и забыть" какого-то кода, но все равно хочу убедиться, что моя память очищена (за Почему для асинхронного метода делегата требуется вызов EndInvoke?), достигнет ли следующая цель?

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

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

Спасибо!

Ответ 1

Использование преобразования группы методов вместо делегата в порядке, 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 нет.