C# 优雅地处理异常的问题

C# 优雅地处理异常的问题,c#,exception,C#,Exception,我正在开发一个应用程序,它使用NAudio将麦克风的输入记录到.wav文件中。我的Recorder类使用BackgroundWorker进行录制。我开始录制并一直录制,直到10秒过去,或者用户请求取消。这在大多数情况下都很好,只有一种情况除外。在调试中,当我中途拔下录音设备时,一切都没有进展。我希望在BackgroundWorkedCompletedTask方法中,如果worker完成事件args为e.Error(如果我抛出任何标准异常,这可以正常工作),就会发现问题,但事实并非如此。当我选择“

我正在开发一个应用程序,它使用NAudio将麦克风的输入记录到.wav文件中。我的Recorder类使用BackgroundWorker进行录制。我开始录制并一直录制,直到10秒过去,或者用户请求取消。这在大多数情况下都很好,只有一种情况除外。在调试中,当我中途拔下录音设备时,一切都没有进展。我希望在BackgroundWorkedCompletedTask方法中,如果worker完成事件args为e.Error(如果我抛出任何标准异常,这可以正常工作),就会发现问题,但事实并非如此。当我选择“全部中断”时,它会将我带到BackgroundWorkedCompletedTask方法,在
this.waveIn.StopRecording()行,并且对象上的所有属性显示为无法计算表达式,因为本机帧位于调用堆栈的顶部。

我假设这与NAudio使用非托管代码与设备交互有关;我希望你能就如何处理这种情况提供指导或建议。在这里,try/catch块似乎不起作用,那么我应该在哪里处理它呢?提前感谢您的帮助

为完整起见,以下是涉及的代码的两个相关部分:

private void RecordUsingBackgroundWorker(BackgroundWorker worker)
{
   var devices = this.FindDevices();
   var deviceIndex = devices.IndexOf(this.requestedDevice);
   var waveIn = new WaveIn(WaveCallbackInfo.FunctionCallback());
   waveIn.DeviceNumber = deviceIndex;
   waveIn.WaveFormat = new WaveFormat(8000, 1);
   this.waveIn = waveIn;

   this.waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(DataIsAvailable);

   var filename = Globals.ThisAddIn.CommentFilePath;
   this.waveFileWriter = new WaveFileWriter(filename, waveIn.WaveFormat);

   var stopwatch = new Stopwatch();
   stopwatch.Start();

   this.waveIn.StartRecording();
   while (stopwatch.ElapsedMilliseconds < 10000 && !worker.CancellationPending)
   {
   }
}

如果对StopRecording的调用被阻塞,一个选项是将其包装在异步调用中,并等待其完成,并超时:

    public bool WaitFor(Action action, TimeSpan timeout)
    {
        var waitHandle = new AutoResetEvent(false);
        ThreadPool.QueueUserWorkItem(state =>
        {
            action();
            waitHandle.Set();
        });

        return waitHandle.WaitOne(timeout);
    }
您可以这样使用它:

        if (!WaitFor(this.waveIn.StopRecording, TimeSpan.FromSeconds(2)))
            throw new TimeoutException("Timed out waiting for recording to stop");

请注意,这会使线程池线程在超时的操作上被阻塞,因此您可能需要调用一个API方法来取消挂起的操作(如果存在),或者应该礼貌地继续关闭应用程序(因为您的线程处于暂停状态,应用程序状态可能会受到影响)在实际的生产场景中,最好进一步改进此方法,以便在超时后任务是否完成时获得肯定的确认(如果您可以调用某种形式的取消,则此方法非常有用)。

Hmya,我以前见过NAudio的类似问题。它使用mmsystem的方式使得死锁非常常见。不太确定它应该受到责备,它以文档化的方式使用API。这只是一种很少受到考验的方式。音频驱动程序也是一个常见的麻烦源,激烈的竞争似乎没有给一个好的软件工程师留下多少钱

当设备在使用时拔下插头总是一个问题,就像在写入时将闪存驱动器从USB插槽中拔出一样。或者在端口打开时拔下USB串行端口模拟器。在使用设备时拔掉设备插头的冲动似乎是不可抗拒的。尽管他们在尝试了几次之后会对它感到厌烦

也许Larry Osterman有一些意见,他在音频层做了很多工作。他在这里发帖,你可以在他的博客上留言,引导他回答这个问题。除此之外,您还需要找到一种方法让NAudio作者与Microsoft支持部门合作。或者自己解决这个问题,提供源代码是有原因的。祝你好运

        if (!WaitFor(this.waveIn.StopRecording, TimeSpan.FromSeconds(2)))
            throw new TimeoutException("Timed out waiting for recording to stop");