【问题标题】:How can I fire an event without waiting for the event listeners to run?如何在不等待事件侦听器运行的情况下触发事件?
【发布时间】:2023-03-16 18:47:01
【问题描述】:

我对 .NET (C#) 中的事件有疑问。我不得不为几种情况编写代码,其中我有一个后台任务正在运行并且我想通知主线程或控制器类发生了某些事情,例如任务完成或完成复制文件,但我没有不希望后台任务等待主线程的委托处理事件。

我想做一些类似消息传递的事情:发送消息,但谁在乎他们用它做什么。

例如:

编写一个类来依次处理多个进程,一个接一个。每个进程都需要在后台线程上运行。当工作完成时,会触发一个事件并告诉控制器它已经完成(假设使用 OnCompleted() 方法)

问题在于,如果控制器的事件处理程序用于启动后续进程,则之前进程的 OnComplete 方法会一直停留在调用堆栈上(永远不会完成执行),直到所有进程都完成为止。

在那种情况下,后台任务如何在不将事件引发方法保留在堆栈上的情况下通知控制器类工作已完成?

示例 2:一个备份程序。

后台线程运行以将每个文件复制到目标。后台需要通知 UI 上次复制的文件,但不需要等待 UI 更新。相反,它只想说,“顺便说一句,这里有一些信息。现在,让我回去工作。”事件监听器不应阻塞事件引发器的处理。

【问题讨论】:

    标签: c# events messages


    【解决方案1】:

    对于您的备份程序案例 2。代码示例将异步触发文件副本,一旦复制完成,它就会调用回调方法。在回调中如果你不想等待 UI 更新,那么你将不得不异步调用 UI 更新代码

    您可以使用异步委托

    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)
            }
        }
    

    你可以这样称呼它:

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

    这个link告诉你异步编码的不同技术

    【讨论】:

      【解决方案2】:

      您可以在引发事件时执行异步调用(如前所述),或者只是在后台线程上引发事件本身:

      void OnUpdated(EventArgs e) {
         EventHandler h = this.Updated;
         if (h != null) h(e);
      }
      
      void DoStuff() {
         BigMethod();
         ThreadPool.QueueUserWorkItem(OnUpdated, EventArgs.Empty);
         BigMethod2();
      }
      

      如果您异步引发,多个侦听器将同时处理您的事件。至少,这需要一个线程安全的 EventArg 类。如果您希望它们也与您的类进行交互,那么您应该非常仔细地记录或使其成为线程安全的。

      在后台线程上引发事件对您的类方法有同样的警告,但您不必担心 EventArgs 类本身。

      【讨论】:

        【解决方案3】:

        听起来您正在尝试异步调用事件调用列表中的委托。

        我建议你阅读.NET Asynchronous Events To Send Process Status To User Interface:

        .NET Framework 为我们提供了 引发事件的概念(和其他 items)在我们的类中异步。 这意味着我们可以引发事件 以这样的方式没有 该事件的订阅者(通常 用户界面) 以提出的方法处理 事件。好处是它 不会对 我们业务层的表现 方法。

        【讨论】:

        • 我已经阅读过 BeginInvoke/EndInvoke 模式,但我正在考虑在侦听器端使用它,而不是在投掷端。如果有大量未完成的 BeginInvoke 调用,会不会有问题?
        【解决方案4】:

        让第一个事件除了启动线程之外什么都不做,那么有什么其他事件侦听器就无关紧要了。

        【讨论】:

        • 好吧,您似乎知道如何启动另一个线程。只需让第一个事件侦听器执行此操作(一旦使用事件创建对象,分配处理程序
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-09-06
        • 1970-01-01
        • 1970-01-01
        • 2015-12-18
        • 2013-05-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多