规避异常和"功能评价超时"异常、评价、功能、QUOT

2023-09-05 01:06:19 作者:匿名网友

在我的实用程序库(Shd.dll)我有一类称为的AsyncOperation。简单地说,它是为封装一个潜在的长期运行的操作类型的基类,执行它在后台线程,并支持暂停/恢复,取消和进度报告。 (这就像一个BackgroundWorker,才知道更多的事情。)

In my utilities library (Shd.dll) I have a class called AsyncOperation. To put it simply, it's a base class for types that encapsulate a potentially long running operation, executes it on a background thread, and it supports pause/resume, cancellation and progress reporting. (It's like a BackgroundWorker, just knows more things.)

在用户code,你可以用它是这样的:

In the user code you can use it like this:

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()不正是它的名字所暗示的:如果取消()早前被另一个线程调用,它抛出一个内部异常(AsyncOperationCancelException),然后通过的AsyncOperation类型处理,类似这样的:

operationState.ThrowIfCancelled() does exactly what its name suggests: if Cancel() was called earlier by another thread, it throws an internal exception (AsyncOperationCancelException), which is then handled by the AsyncOperation type, like this:

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

这完美的作品。或者说,我认为在过去的一年,而我在很多情况下使用这个。

This works perfectly. Or so I thought for the past year, while I was using this in numerous scenarios.

我要建一个使用System.Net.WebClient通过FTP上传潜在的大量文件的类。这个类是使用如上所述的AsyncOperation基类建

I'm building a class that uses System.Net.WebClient to upload potentially large number of files via FTP. This class is built using the AsyncOperation base class as described above.

有关精确的进度报告,我用WebClient.UploadFileAsync(),其中复杂的code,但相关的部分是这样的:

For accurate progress reports, I use WebClient.UploadFileAsync(), which complicates the code, but the relevant parts look like this:

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秒钟,然后接下来的事情我看到的是源$ C $ AsyncOperationState.ThrowIfCancelled()的C:

As you can see, I marked the line where the crash occurs. What exactly happens is that when execution hits that line (I put a break point right over it, so I know this is the exact line), Visual Studio 2010 freezes for about 15 seconds, and then the next thing I see is the source code of 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 {}块。

I tried putting breakpoints to where the exception should have been caught, but the execution never reaches that catch {} block.

另一个奇怪这是在最后还写了以下内容:函数求禁用的,因为一个previous功能评价超时我用Google搜索这个问题,并试图一切都被认为(禁止隐性财产评估,移除所有断点),但没有到目前为止帮助。

The other weird this is that at the end it also writes the following: "Function evaluation disabled because a previous function evaluation timed out." I Googled this problem, and tried everything that was suggested (disabled implicit property evaluation, removed all breakpoints), but nothing helped so far.

下面是两个截图,说明这个问题: https://m.xsw88.com/allimgs/daicuo/20230905/528.png https://m.xsw88.com/allimgs/daicuo/20230905/529.png

Here are two screenshots that illustrate the problem: https://m.xsw88.com/allimgs/daicuo/20230905/528.png https://m.xsw88.com/allimgs/daicuo/20230905/529.png

我使用.NET 4.0。任何帮助将非常AP preciated。

I'm using .NET 4.0. Any help would be very much appreciated.

推荐答案

在Visual Studio调试器附加到一个应用程序,它就会通知时抛出一个异常,运行code得到机会处理之前, 。这就是所谓的 第一次机会异常 ,和VS可配置中断执行时有一定的异常类型被抛出。

When the Visual Studio debugger is attached to an application, it gets notified whenever an exception is thrown, before the running code gets the chance to handle it. This is called a first-chance exception, and VS can be configured to break execution when a certain exception type is thrown.

您可以指定调试器行为的每个异常使用例外窗口(调试菜单),分别输入。默认情况下,所有异常的用户未处理的复选框选中,这意味着只有未处理例外情况将打破执行。设置抛出复选框某种类型的异常势力VS中断执行,即使异常会被处理,但仅限于该异常类型(不适用于派生类型)。如果处理程序存在,一旦你恢复执行(由pressing F5),异常会被正常捕获。

You can specify debugger behavior for each exception type separately using the Exceptions window (Debug menu). By default, all exceptions have the "User-unhandled" checkbox checked, meaning that only unhandled exceptions will break execution. Setting the "Thrown" checkbox for a certain exception type forces VS to break execution even if the exception will be handled, but only for that exception type (not for derived types). If a handler exists, once you resume execution (by pressing F5), the exception will be caught normally.

我猜想,您的自定义异常添加到例外窗口异常(您可以通过使用窗口中的查找按钮检查)的列表。

I would guess that your custom exception was added to the list of exceptions in the Exceptions window (which you can check by using the Find button inside the window).

根据我的测试,它也发生在 DynamicInvoke 用在 .NET 4 ,无论例外窗口设置。昨天我用VS2008,我不能复制它,但它似乎像现在这样奇怪的行为。

According to my tests, it also happens when DynamicInvoke is used in .NET 4, regardless of the Exceptions window setting. Yesterday I was using VS2008 and I couldn't reproduce it, but it does seem like odd behavior now.

这是测试我试过(对不起短暂的格式,但它是非常简单):

This is the test I tried (sorry for the brief formatting, but it's fairly simple):

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 code有以前版本4之间变化,但并没有什么这将说明为什么VS2010的调试器是无法看到有这个方法调用中的异常处理程序

My only guess is that exception handling done inside InvokeMethodFast (which is an InternalCall method) has somehow changed. DynamicInvoke code has changed between versions 4 and prior, but there is nothing which would indicate why VS2010 debugger is unable to see that there is an exception handler inside that method call.