在finally块中抛出异常

发布于 2024-08-17 10:25:05 字数 1388 浏览 4 评论 0原文

有没有办法获取当前抛出的异常(如果存在)?

我想减少代码量并对任务进行一些重用,如下所示:

Exception thrownException = null;
try {
    // some code with 3rd party classes, which can throw unexpected exceptions
}
catch( Exception exc ) {
    thrownException = exc;
    LogException( exc );
}
finally {
    if ( null == thrownException ) {
        // some code
    }
    else {
        // some code
    }
}

并将其替换为以下代码:

using( ExceptionHelper.LogException() ) {
    // some code with 3rd party classes, which can throw unexpected exceptions
}
using( new ExceptionHelper { ExceptionAction = ()=> /*some cleaning code*/ } ) {
    // some code with 3rd party classes, which can throw unexpected exceptions
}

public class ExceptiohHelper : IDisposable {
    public static ExceptionHelper LogException() {
        return new ExceptionHelper();
    }

    public Action SuccessfulAction {get; set;}
    public Action ExceptionAction {get; set;}

    public void Dispose() {
        Action action;
        Exception thrownException = TheMethodIDontKnow();
        if ( null != thrownException ) {
            LogException( thrownException );
            action = this.ExceptionAction;
        }
        else {
            action = this.SuccessfulAction;
        }

        if ( null != action ) {
            action();
        }
    }
}

这种情况可能吗?

谢谢

Is there a way, how to get currently thrown exception (if exists)?

I would like reduce amount of code and apply some reuse for task looks like:

Exception thrownException = null;
try {
    // some code with 3rd party classes, which can throw unexpected exceptions
}
catch( Exception exc ) {
    thrownException = exc;
    LogException( exc );
}
finally {
    if ( null == thrownException ) {
        // some code
    }
    else {
        // some code
    }
}

and replace it with this code:

using( ExceptionHelper.LogException() ) {
    // some code with 3rd party classes, which can throw unexpected exceptions
}
using( new ExceptionHelper { ExceptionAction = ()=> /*some cleaning code*/ } ) {
    // some code with 3rd party classes, which can throw unexpected exceptions
}

public class ExceptiohHelper : IDisposable {
    public static ExceptionHelper LogException() {
        return new ExceptionHelper();
    }

    public Action SuccessfulAction {get; set;}
    public Action ExceptionAction {get; set;}

    public void Dispose() {
        Action action;
        Exception thrownException = TheMethodIDontKnow();
        if ( null != thrownException ) {
            LogException( thrownException );
            action = this.ExceptionAction;
        }
        else {
            action = this.SuccessfulAction;
        }

        if ( null != action ) {
            action();
        }
    }
}

Is this scenario posible?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

红焚 2024-08-24 10:25:05

这个想法是在 catch 块中处理异常...

也就是说,Exception 是引用类型,因此您始终可以在 try 范围之外声明 Exception 变量...

Exception dontDoThis;
try
{
    foo.DoSomething();
}
catch(Exception e)
{
    dontDoThis = e;
}
finally
{
    // use dontDoThis...
}

The idea is that you handle exceptions in the catch block...

That said, Exception is a reference type, so you can always declare an Exception variable outside the try scope...

Exception dontDoThis;
try
{
    foo.DoSomething();
}
catch(Exception e)
{
    dontDoThis = e;
}
finally
{
    // use dontDoThis...
}
青朷 2024-08-24 10:25:05

对于下面的事情你有什么看法呢。不要将问题视为“如何获取最后一个异常?”,而是将其更改为“如何通过更多控制来运行一段代码?”会怎样?

例如:
您可以使用 ActionRunner,而不是 ExceptionHelper。

public class ActionRunner
{
    public Action AttemptAction { get; set; }
    public Action SuccessfulAction { get; set; }
    public Action ExceptionAction { get; set; }

    public void RunAction()
    {
        try
        {
            AttemptAction();
            SuccessfulAction();
        }
        catch (Exception ex)
        {
            LogException(ex);
            ExceptionAction();
        }
    }

    private void LogException(Exception thrownException) { /* log here... */ }
}

假设只有 AttemptAction 在调用之间有所不同,它至少会给您一些 SuccessAction 和 ExceptionAction 的重用。

var actionRunner = new ActionRunner
{
    AttemptAction = () =>
    {
        Console.WriteLine("Going to throw...");
        throw new Exception("Just throwing");
    },
    ExceptionAction = () => Console.WriteLine("ExceptionAction"),
    SuccessfulAction = () => Console.WriteLine("SuccessfulAction"),
};
actionRunner.RunAction();

actionRunner.AttemptAction = () => Console.WriteLine("Running some other code...");
actionRunner.RunAction();

What do you think about the following. Instead of looking at the problem as "How to get the last exception?", what if you change it to, "How do I run some piece of code with some more control?"

For example:
Instead of an ExceptionHelper you could have an ActionRunner.

public class ActionRunner
{
    public Action AttemptAction { get; set; }
    public Action SuccessfulAction { get; set; }
    public Action ExceptionAction { get; set; }

    public void RunAction()
    {
        try
        {
            AttemptAction();
            SuccessfulAction();
        }
        catch (Exception ex)
        {
            LogException(ex);
            ExceptionAction();
        }
    }

    private void LogException(Exception thrownException) { /* log here... */ }
}

It would at least give you some reuse of the SuccessfulAction and ExceptionAction assuming only the AttemptAction varies between calls.

var actionRunner = new ActionRunner
{
    AttemptAction = () =>
    {
        Console.WriteLine("Going to throw...");
        throw new Exception("Just throwing");
    },
    ExceptionAction = () => Console.WriteLine("ExceptionAction"),
    SuccessfulAction = () => Console.WriteLine("SuccessfulAction"),
};
actionRunner.RunAction();

actionRunner.AttemptAction = () => Console.WriteLine("Running some other code...");
actionRunner.RunAction();
幸福不弃 2024-08-24 10:25:05

如果您希望捕获意外异常,则应该处理 UnhandledException 。您应该只在您打算处理的较低级别捕获异常(而不仅仅是记录),否则您应该让它们冒泡并在较高级别捕获,或者正如我之前在 UnhandledException 方法中提到的那样。

If you are looking to catch unexpected exceptions you should be handling the UnhandledException. You should only catch exceptions at lower levels that you intend handle (not just to log), otherwise you should let them bubble up and be caught at a higher level, or as I mentioned before in the UnhandledException method.

揪着可爱 2024-08-24 10:25:05

这是一个非常古老的问题,但现在有一些可能性。

此 github 问题包含如何实现此目的的示例:

async Task Main()
{
    using var activity1 = new Activity();
    try
    {
        using var activity2 = new Activity();
        await ThrowAsync();
    }
    catch
    {       
    }
}

public Task ThrowAsync() => Task.Run(() => throw new OperationCanceledException());

public sealed class Activity : IDisposable
{
    [ThreadStatic]
    private static GCHandle _currentExceptionHandle;
    
    static Activity()
    {
        AppDomain.CurrentDomain.FirstChanceException += (s,e) =>
        {
            if (_currentExceptionHandle.IsAllocated)
            {
                _currentExceptionHandle.Free();
            }
            _currentExceptionHandle = GCHandle.Alloc(e.Exception, GCHandleType.Weak);
        };
    }
    
    private readonly IntPtr _exceptionAddress;

    public Activity()
    {
        _exceptionAddress = Marshal.GetExceptionPointers();
    }

    public void Dispose()
    {
        var curentExceptionAddr = Marshal.GetExceptionPointers();
        var isExceptionBubblingUp = _exceptionAddress != curentExceptionAddr && curentExceptionAddr != IntPtr.Zero;
        if (isExceptionBubblingUp && _currentExceptionHandle.Target is Exception currentException)
        {
            Console.WriteLine($"Thrown exception {currentException}");
        }
        else if (_currentExceptionHandle.IsAllocated)
        {
            _currentExceptionHandle.Free();
        }
    }
}

It's a very old question, but these days there are some possibilities.

This github issue contains an example of how this can be achieved:

async Task Main()
{
    using var activity1 = new Activity();
    try
    {
        using var activity2 = new Activity();
        await ThrowAsync();
    }
    catch
    {       
    }
}

public Task ThrowAsync() => Task.Run(() => throw new OperationCanceledException());

public sealed class Activity : IDisposable
{
    [ThreadStatic]
    private static GCHandle _currentExceptionHandle;
    
    static Activity()
    {
        AppDomain.CurrentDomain.FirstChanceException += (s,e) =>
        {
            if (_currentExceptionHandle.IsAllocated)
            {
                _currentExceptionHandle.Free();
            }
            _currentExceptionHandle = GCHandle.Alloc(e.Exception, GCHandleType.Weak);
        };
    }
    
    private readonly IntPtr _exceptionAddress;

    public Activity()
    {
        _exceptionAddress = Marshal.GetExceptionPointers();
    }

    public void Dispose()
    {
        var curentExceptionAddr = Marshal.GetExceptionPointers();
        var isExceptionBubblingUp = _exceptionAddress != curentExceptionAddr && curentExceptionAddr != IntPtr.Zero;
        if (isExceptionBubblingUp && _currentExceptionHandle.Target is Exception currentException)
        {
            Console.WriteLine(
quot;Thrown exception {currentException}");
        }
        else if (_currentExceptionHandle.IsAllocated)
        {
            _currentExceptionHandle.Free();
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文