gpt4 book ai didi

c# - 回避异常和 "a function evaluation has timed out"

转载 作者:行者123 更新时间:2023-11-30 14:15:47 25 4
gpt4 key购买 nike

背景

在我的实用程序库 (Shd.dll) 中,我有一个名为 AsyncOperation 的类。简而言之,它是封装潜在长时间运行操作的类型的基类,在后台线程上执行它,并且它支持暂停/恢复、取消和进度报告。 (它就像一个BackgroundWorker,只是知道更多的东西。)

在用户代码中你可以这样使用它:

class MyOperation : AsyncOperation
{
public MyOperation() : base(null, AsyncOperationOptions.Cancelable | AsyncOperationOptions.Pausable) {}

protected override void RunOperation(AsyncOperationState operationState, object userState)
{
...
operationState.ThrowIfCancelled();
}
}

var op = new MyOperation();
op.Start();
...
op.Cancel();

operationState.ThrowIfCancelled() 的作用正如它的名字所暗示的:如果 Cancel() 之前被另一个线程调用,它会抛出一个内部异常 (AsyncOperationCancelException),然后由 AsyncOperation 类型处理,如下所示:

private void _DoExecute(object state)
{
// note that this method is already executed on the background thread
...
try
{
operationDelegate.DynamicInvoke(args); // this is where RunOperation() is called
}
catch(System.Reflection.TargetInvocationException tiex)
{
Exception inner = tiex.InnerException;
var cancelException = inner as AsyncOperationCancelException;
if(cancelException != null)
{
// the operation was cancelled
...
}
else
{
// the operation faulted
...
}
...
}
...
}

这非常有效。在过去的一年里,当我在许多场景中使用它时,我是这么想的。

实际问题

我正在构建一个使用 System.Net.WebClient 通过 FTP 上传可能大量文件的类。如上所述,此类是使用 AsyncOperation 基类构建的。

为了获得准确的进度报告,我使用 WebClient.UploadFileAsync(),这使代码变得复杂,但相关部分如下所示:

private ManualResetEventSlim completedEvent = new ManualResetEventSlim(false);

private void WebClient_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
...
if (OperationState.IsCancellationRequested)
{
_GetCurrentWebClient().CancelAsync();
}
}

private void WebClient_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
{
...
_UploadNextFile();
}

private void _UploadNextFile()
{
if (OperationState.IsCancellationRequested || ...)
{
this.completedEvent.Set();
return;
}
...
}

protected override void RunOperation(AsyncOperationState operationState, object userState)
{
...
_UploadNextFile();
this.completedEvent.Wait();

operationState.ThrowIfCancelled(); // crash
...
}

如您所见,我标记了发生崩溃的行。确切发生的是,当执行到该行时(我在它上面放了一个断点,所以我知道这是确切的行),Visual Studio 2010 卡住了大约 15 秒,然后我看到的下一件事是源代码AsyncOperationState.ThrowIfCancelled() 的:

public void ThrowIfCancelled()
{
if(IsCancellationRequested)
{
throw new AsyncOperationCancelException();
}
} // this is the line the debugger highlights: "An exception of type AsyncOperationCancelException' occured in Shd.dll but was unhandled by user code."

我尝试将断点放置在本应捕获异常的位置,但执行从未到达那个 catch {} block 。

另一个奇怪的是,它最后还写了以下内容:“由于先前的函数评估超时,函数评估被禁用。”我用 Google 搜索了这个问题,并尝试了所有建议的方法(禁用隐式属性评估、删除所有断点),但到目前为止没有任何帮助。

这里有两个截图可以说明这个问题:
http://dl.dropbox.com/u/17147594/vsd1.png
http://dl.dropbox.com/u/17147594/vsd2.png

我正在使用 .NET 4.0。非常感谢任何帮助。

最佳答案

当 Visual Studio 调试器附加到应用程序时,只要抛出异常,它就会在运行代码有机会处理它之前得到通知。这称为 first-chance exception , 并且 VS 可以配置为在抛出特定异常类型时中断执行。

您可以使用 Exceptions 窗口(调试菜单)分别为每个异常类型指定调试器行为。默认情况下,所有异常都选中了“用户未处理”复选框,这意味着只有未处理 异常才会中断执行。为某种异常类型设置“抛出”复选框会强制 VS 中断执行,即使异常将被处理,但仅限于该异常类型(不适用于派生类型)。如果处理程序存在,一旦您恢复执行(通过按 F5),异常将被正常捕获。

我猜您的自定义异常已添加到异常窗口中的异常列表中(您可以使用窗口内的 Find 按钮进行检查)。

[编辑]

根据我的测试,在 .NET 4 中使用 DynamicInvoke 时也会发生这种情况,无论 Exceptions 窗口设置如何。昨天我使用的是 VS2008,我无法重现它,但现在看起来确实很奇怪。

这是我试过的测试(很抱歉格式很短,但它相当简单):

Action<int> a = i => { throw new ArgumentException(); };

// When the following code is executed, VS2010 debugger
// will break on the `ArgumentException` above
// but ONLY if the target is .NET 4 (3.5 and lower don't break)
try { a.DynamicInvoke(5); }
catch (Exception ex)
{ }

// this doesn't break
try { a.Invoke(5); }
catch (Exception ex)
{ }

// neither does this
try { a(5); }
catch (Exception ex)
{ }

我唯一的猜测是在 InvokeMethodFast(这是一个 InternalCall 方法)内部完成的异常处理已经不知何故发生了变化。 DynamicInvoke 代码在版本 4 和之前的版本之间发生了变化,但没有任何迹象表明为什么 VS2010 调试器无法看到该方法调用中存在异常处理程序。

关于c# - 回避异常和 "a function evaluation has timed out",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9352087/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com