Если объект создан и имеет события, назначенные в одном потоке, а затем запускается из другого потока, в каком потоке запускается событие? - PullRequest
1 голос
/ 13 мая 2011

Если я создаю объект в основном потоке пользовательского интерфейса, а затем вызываю метод в этом объекте из другого потока, будут ли возникать какие-либо возникшие события в отдельном потоке или главном потоке пользовательского интерфейса?

Пример:

WebClient client = new WebClient();
client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(
    delegate(object sender, DownloadDataCompletedEventArgs e)
    {
        Thread.Sleep(60000);
    });
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(
    delegate(object sender, DoWorkEventArgs e)
    {
        Thread.Sleep(60000);
        client.DownloadDataAsync("http://www.example.com");
    });
worker.RunWorkerAsync();

Будет ли какая-то разница в подключении событий к их собственным методам вместо делегатов?

Спасибо.

Ответы [ 2 ]

2 голосов
/ 13 мая 2011

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

Вы также можете вызвать событие асинхронно с помощью BeginInvoke , в этом случае я полагаю, что он обрабатывается «в конечном итоге» потоком из приложения пул потоков .

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

Это можно сделать с помощью метода Control.InvokeRequired / Control.Invoke (...), См.

1 голос
/ 13 мая 2011

Обработчики событий запускаются в потоке, который их вызывает, как и любой другой метод.Однако, если обработчик определен в классе, который реализует ISynchronizeInvoke (например, элементы управления winforms), вы можете вызвать его в потоке, который его создал.Вот метод расширения, который я использую для вызова событий, который автоматически обрабатывает это:

    /// <summary>
    /// Fires an event and catches any exceptions raised by an event handler.
    /// </summary>
    /// <param name="ev">The event handler to raise</param>
    /// <param name="sender">The sender of the event.</param>
    /// <param name="e">Event arguments for the event.</param>
    /// <typeparam name="T">The type of the event args.</typeparam>
    public static void Fire<T>(this EventHandler<T> ev, object sender, T e) where T : EventArgs
    {
        if (ev == null)
        {
            return;
        }

        foreach (Delegate del in ev.GetInvocationList())
        {
            try
            {
                ISynchronizeInvoke invoke = del.Target as ISynchronizeInvoke;
                if (invoke != null && invoke.InvokeRequired)
                {
                    invoke.Invoke(del, new[] { sender, e });
                }
                else
                {
                    del.DynamicInvoke(sender, e);
                }
            }
            catch (TargetInvocationException ex)
            {
                ex.InnerException.PreserveStackTrace();
                throw ex.InnerException;
            }
        }
    }

    /// <summary>
    /// Called on a <see cref="TargetInvocationException"/> to preserve the stack trace that generated the inner exception.
    /// </summary>
    /// <param name="e">The exception to preserve the stack trace of.</param>
    public static void PreserveStackTrace(this Exception e)
    {
        var ctx = new StreamingContext(StreamingContextStates.CrossAppDomain);
        var mgr = new ObjectManager(null, ctx);
        var si = new SerializationInfo(e.GetType(), new FormatterConverter());

        e.GetObjectData(si, ctx);
        mgr.RegisterObject(e, 1, si);
        mgr.DoFixups();
    }

РЕДАКТИРОВАТЬ: функция PreserveStackTrace на самом деле не является частью ответа на этот вопрос, это лишь часть решения, которое я использую.Я на самом деле получил этот метод из другого ответа на SO, хотя я не могу точно вспомнить, откуда, но заслуга в этом действительно принадлежит кому-то еще.Извините, я не могу вспомнить, кто.

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