Как ждать обработки события в c# - PullRequest
1 голос
/ 25 марта 2020

Давайте представим, что у нас есть такой код:

public class MyProcess
{
    private Process _process;
    public event EventHandler OnFinish;
    public MyProcess(string pathToExe)
    {
         _process = new Process();
         _process.StartInfo.FileName = pathToExe;
    }
    public int Start()
    {
         _process.Exited += _processExited;
         _process.Start();
         return _process.Id;
    }
    public void Stop()
    {
         _process.Stop();
    }
    private void _processExited(object sender, EventArgs e)
    {
         OnFinish?.Invoke();
    }
}

public class MyProgram
{
    private static int stoppedProcs = 0;

    public static void Main(string[] args)
    {
         var proc = new MyProcess("foo.exe");
         proc.OnFinish += proc_OnFinish;
         proc.Start();
         proc.Stop();
         //Wait here to display 1 instead of 0
         Console.WriteLine(stoppedProcs);
    }

    private static void proc_OnFinish(object sender, EventArgs e)
    {
         stoppedProcs++;
    }
}

Я создаю и запускаю процесс. Затем я хочу остановить это и продолжить только после того, как обработаю событие. Проблема в том, что я не вызываю событие самостоятельно, как это делает ОС. Как понять, что обработчики событий завершены?

Ответы [ 3 ]

1 голос
/ 25 марта 2020

Предполагая, что вы хотите ждать синхронно (блокируя текущий поток), просто предоставьте через ваш класс метод Process.WaitForExit.

public void WaitForExit()
{
    _process.WaitForExit();
}
0 голосов
/ 26 марта 2020

Спасибо всем за ответ на мой вопрос. Проблема была легко решена с предложением @Fildor использовать ManualResetEvent

public class MyProgram
{
private static int stoppedProcs = 0;
private static ManualResetEvent mre = new ManualResetEvent(false);
public static void Main(string[] args)
{
     var proc = new MyProcess("foo.exe");
     proc.OnFinish += proc_OnFinish;
     proc.Start();
     proc.Stop();
     //Wait here to display 1 instead of 0
     mre.WaitOne();
     mre.Reset();
     Console.WriteLine(stoppedProcs);
}

private static void proc_OnFinish(object sender, EventArgs e)
{
     stoppedProcs++;
     mre.Set();
}
}
0 голосов
/ 25 марта 2020

Чтобы расширить ответы с упоминанием Task и await вещи

Если вы хотите превратить ожидание в асинхронный поток c, вы можете объединить событие Exited с TaskCompletionSource следующим образом:

public static class ProcessExtension
{
    public static Task WaitForExitAsync(this Process proc, Action callback)
    {
        return new WaitForExitExt(proc, callback).WaitTask;
    }

    class WaitForExitExt
    {
        private TaskCompletionSource<int> _tcs;
        private Action _callback;

        public WaitForExitExt(Process proc, Action callback)
        {
            _callback = callback;
            proc.EnableRaisingEvents = true;

            _tcs = new TaskCompletionSource<int>();

            if (proc.HasExited)
            {
                _tcs.TrySetResult(proc.ExitCode);
            }
            else
            {
                proc.Exited += OnProcessExited;

                // Process already exited by the time the handler was attached.
                if (proc.HasExited)
                {
                    proc.Exited -= OnProcessExited;
                    _tcs.TrySetResult(proc.ExitCode);
                }
            }
        }

        public Task WaitTask => _tcs.Task;

        private void OnProcessExited(object sender, EventArgs e)
        {
            var proc = (Process)sender;
            proc.Exited -= OnProcessExited;

            _callback();

            _tcs.TrySetResult(proc.ExitCode);
        }
    }
}

Вышеприведенное расширение позволяет запускать callback после завершения процесса, и гарантированно будет выполняться callback до завершения задачи, так что вы можете использовать его в своем коде, например:

var process = new Process();
process.StartInfo.FileName = "notepad.exe";
process.EnableRaisingEvents = true;
process.Start();

var task = process.WaitForExitAsync(() => Console.WriteLine("Exited"));
process.Kill();
await task;

Console.WriteLine("Task finished");

И вывод:

Exited
Task finished
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...