Resharper异常重新抛出可能是有意的

时间:2009-11-21 20:03:38

标签: c# exception resharper

考虑这种方法(原谅Chuck Norris幽默的悲惨尝试:)):

public class ChuckNorrisException : Exception
{
    public ChuckNorrisException()
    {
    }

    public ChuckNorrisException(string message)
        : base(message)
    {
    }

    public ChuckNorrisException(string message, Exception cause)
        : base(message, cause)
    {
    }

    protected ChuckNorrisException(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
    }
}

static void ExceptionTest(double x)
{
    try
    {
        double y = 10 / x;
        Console.WriteLine("quotient = " + y);
    }
    catch (Exception e)
    {
        e = e is DivideByZeroException ? new ChuckNorrisException("Only Chuck Norris can divide by 0!", e) :
            e;
        throw e;
    }
}

在resharper中,我收到一条警告“throw e”行说“异常重新抛出可能意图”。但显然在这种情况下并不是意图,因为e可能被包装在ChuckNorrisException中,如果我只是使用“throw”,那么包装的异常就不会被抛出。

我知道我可以抑制resharper警告,但是如果我没有弄错的话,所有场景将关闭它。我只是想知道是否还有其他人遇到过此事。我发现的唯一解决方法是创建另一个异常变量(例如e2),然后抛出它。这可能是我能在这里做的最好的。似乎resharper可以检测到这个问题并且足够聪明,知道如果e被修改,那么抛出e就可以了。

感谢。

[编辑] 对不起,我忘记了一步。在抛出之前,我需要记录异常,所以我不能这样做:

e = e is DivideByZeroException ? new ChuckNorrisException("Only Chuck Norris can divide by 0!", e) :
            e;
throw e;

我必须这样做:

e = e is DivideByZeroException ? new ChuckNorrisException("Only Chuck Norris can divide by 0!", e) :
            e;
LogException(e);
throw e;

2 个答案:

答案 0 :(得分:31)

也许我不理解这个问题,所以如果我的错误结束,请纠正我。

这里有两种情况:

  1. 首先是你抓住了 原始例外。然后换行 它在一个新的异常实例中 内部异常,然后抛出 新的一个。在这种情况下没有信息丢失(内部异常保留所有信息),因此没有给出警告。

  2. 第二个是你抓住了 重新抛出原始异常。如果你重新投掷,你 永远不应该使用“扔e”,因为它 将篡改堆栈跟踪。 这就是ReSharper打印的原因 警告。要重新抛出捕获的异常,您应该自己使用“throw”关键字。

  3. this question的答案比我更好地解释了它。由于微妙的副作用和错误的人数,我个人认为重新抛出的语法是有缺陷的。

    无论如何,这是对为什么您的警告的描述。以下是我要做的事情:

    catch(DivideByZeroException e)
    {
        // we don't catch any other exceptions because we weren't
        // logging them or doing anything with the exception before re-throwing
        throw new ChuckNorrisException("Useful information", e);
    }
    

    *编辑 - 如果您需要记录异常,您可以执行此类操作。注意:这是我首选的解决方案,因为我认为它读起来更好,并且自己包含错误的可能性低于自己查询异常类型的错误:

    // catch most specific exception type first
    catch(DivideByZeroException e)
    {
        Log(e); 
        throw new ChuckNorrisException("Useful information", e);
    } 
    catch(Exception e) // log & re-throw all other exceptions
    {
        Log(e);
        throw; // notice this is *not* "throw e"; this preserves the stack trace
    }
    

    另一种选择是:

    catch(Exception e)
    {
        Log(e);
        if(e is DivideByZeroException)
        {
            // wrap + throw the exception with our new exception type
            throw new ChuckNorrisException("useful info", e);
        }
    
        // re-throw the original, preserving the stack trace
        throw;
    }
    

答案 1 :(得分:2)

这与您发布的代码具有相同的效果,不应导致警告。

catch (DivideByZeroException de)
    {
        throw new ChuckNorrisException("Only Chuck Norris can divide by 0!", de);
    }
}