How can I fire an event without waiting for the event listeners to run?

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-22 11:26:47

问题


I have a question about events in .NET (C#). I have had to write code for several situations in which I have a background task running and I want to notify a main thread, or controller class, that something has occurred, such as task completed, or finished copying a file, but I don't want the background task to wait for the main thread's delegate to process the event.

I want to do something like message passing: Send the message, but who cares what they do with it.

For example:

A class is written to process several processes in sequence, one after the other. Each process needs to run on a background thread. When work is completed, an event fires and tells the controller that it's done (let's say using OnCompleted() method)

The problem is that if the controller's event handler is used to start the subsequent process, the previous processes' OnComplete method stays on the call stack (never finishes executing) until the all of the processes have completed.

In that situation, how could the background task notify the controller class that the work is done without keeping the event raising method on the stack?

Example 2: A backup program.

A background thread runs to copy each file to the destination. The background needs to notify the UI the last file that was copied, but it doesn't need to wait for the UI to update. Instead, it just wants to say, "BTW, here's some info. Now, let me get back to work." The event listener shouldn't block the processing of the event raiser.


回答1:


You could do an async invoke when raising the event (as mentioned), or just raise the event itself on a background thread:

void OnUpdated(EventArgs e) {
   EventHandler h = this.Updated;
   if (h != null) h(e);
}

void DoStuff() {
   BigMethod();
   ThreadPool.QueueUserWorkItem(OnUpdated, EventArgs.Empty);
   BigMethod2();
}

If you raise asynchronously, multiple listeners would be processing your event at the same time. At the very least, that requires a thread-safe EventArg class. If you expect them to interact with your class as well, then you should document very carefully or make it thread-safe as well.

Raising the event on a background thread carries the same caveats for your class methods, but you don't have to worry about the EventArgs class itself.




回答2:


It sounds like you are trying to invoke the delegates in the event's invocation list asynchronously.

I would suggest that you read .NET Asynchronous Events To Send Process Status To User Interface:

The .NET Framework offers us the concept of raising events (and other items) in our classes asynchronously. This means that we can raise the event in such a way as to not have the subscriber to that event (typically the user interface) hold up the processing in the method that raised the event. The benefit being that it doesn't negatively impact the performance of our business layer method.




回答3:


Have the first event do nothing but kick off the thread, then it doesn't matter what other event listeners there are.




回答4:


For your case 2 of back up program. The code sample will fire a file copy asynchronously and once the copy is done it calls the call back method. In the callback if you dont want to wait for UI to update, then you will have to call the UI updating code asynchronously

You can use asynchronous delegates

public class AsyncFileCopier
    {
        public delegate void FileCopyDelegate(string sourceFile, string destFile);

        public static void AsynFileCopy(string sourceFile, string destFile)
        {
            FileCopyDelegate del = new FileCopyDelegate(FileCopy);
            IAsyncResult result = del.BeginInvoke(sourceFile, destFile, CallBackAfterFileCopied, null);
        }

        public static void FileCopy(string sourceFile, string destFile)
        { 
            // Code to copy the file
        }

        public static void CallBackAfterFileCopied(IAsyncResult result)
        {
            // Notify UI by calling an async del (probably using fire & forget approach or another callback if desired)
        }
    }

You can call it as:

AsyncFileCopier.AsynFileCopy("abc.txt", "xyz.txt");

This link tells you the different techniques of asyn coding



来源:https://stackoverflow.com/questions/890896/how-can-i-fire-an-event-without-waiting-for-the-event-listeners-to-run

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!