Ответ 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
нет.