C#:我如何等待设置事件?

时间:2014-02-21 20:57:19

标签: c# multithreading

我想编写一个调用某些异步产品任务的同步测试。

在下面的示例中,DoSomething()由单独的线程调用,然后设置SomethingCompleted事件。

在我的测试代码中,如何设置SomethingCompleted?

public event Action<Result> SomethingCompleted;

public void DoSomething()
{
    Something();

    this.SomethingCompleted(new Result("Success"));
}

3 个答案:

答案 0 :(得分:2)

using (var evt = new ManualResetEvent()) {
 Action<Result> handler = _ => evt.Set();
 SomethingCompleted += handler;
 evt.WaitOne();
 SomethingCompleted -= handler; //cut object reference to help GC
}

如果需要,您可以在等待完成后取消订阅活动。这样,事件不会使委托和闭包实例保持活动状态。

您可以将其解压缩为可重复使用的辅助方法/扩展名。

答案 1 :(得分:0)

// test case
public void Test() 
{

   var yourObj = new YourObj();
   var done = false;
   Result result;
   yourObj.SomethingCompleted += (finalResult) => {
     result=finalResult; 
     done=true;
   };

   yourObj.DoSomething();

   while(!done) Thread.Sleep(200);

   if(result != theExpectedResult) kaboom();
}

如何订阅活动并“轮询”lambda直到结果可用?这应该有用。

答案 2 :(得分:0)

您使用的是错误类型的事件。您正在使用的事件是回调。在您提供的代码中,附加到SomethingCompleted事件的代理将在与DoSomething相同的线程上调用。

您想要的是使用AutoResetEventManualResetEvent之类的事件进行线程同步,这与您正在使用的框架/语言级事件无关。你可以这样做:

void MainThreadProc()
{
    // create thread synchronization event
    using (var evt = new ManualResetEvent(false))
    {
        // start background operation
        ThreadPool.QueueUserWorkItem(BackgroundThreadProc, evt);

        // this line will block until BackgroundThreadProc sets the event
        evt.WaitOne();
    }

    // resume main thread operations here
    ...
}

void BackgroundThreadProc(object o)
{
    // get event from argument
    var evt = (ManualResetEvent) o;

    // do the deed
    ...

    // set event to signal completion
    evt.Set();
}

这只是众多不同方法中的一种。替代方案包括并行LINQ或任务并行库(两者最好用于并行操作,而不仅仅是单个后台操作)。如果您不想阻止主线程,请查看BackgroundWorker