我正在看关于可序列化dto的文章c# -数据传输对象。

这篇文章包含了下面这段代码:

public static string SerializeDTO(DTO dto) {
    try {
        XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
        StringWriter sWriter = new StringWriter();
        xmlSer.Serialize(sWriter, dto);
        return sWriter.ToString();
    }
    catch(Exception ex) {
        throw ex;
    }
}

文章的其余部分看起来理智而合理(对于新手来说),但是try-catch-throw抛出了一个WtfException…这不完全等同于不处理异常吗?

结论:

public static string SerializeDTO(DTO dto) {
    XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
    StringWriter sWriter = new StringWriter();
    xmlSer.Serialize(sWriter, dto);
    return sWriter.ToString();
}

还是我错过了c#中错误处理的一些基本内容?它与Java非常相似(减去受控异常),不是吗?... 也就是说,它们都改进了c++。

堆栈溢出问题重新抛出无参数catch和什么都不做之间的区别?这似乎支持了我的观点,试着接球是不行的。


编辑:

只是为了给将来找到这条线索的人做个总结…

try {
    // Do stuff that might throw an exception
}
catch (Exception e) {
    throw e; // This destroys the strack trace information!
}

堆栈跟踪信息对于确定问题的根本原因至关重要!

DO

try {
    // Do stuff that might throw an exception
}
catch (SqlException e) {
    // Log it
    if (e.ErrorCode != NO_ROW_ERROR) { // filter out NoDataFound.
        // Do special cleanup, like maybe closing the "dirty" database connection.
        throw; // This preserves the stack trace
    }
}
catch (IOException e) {
    // Log it
    throw;
}
catch (Exception e) {
    // Log it
    throw new DAOException("Excrement occurred", e); // wrapped & chained exceptions (just like java).
}
finally {
    // Normal clean goes here (like closing open files).
}

在不太特定的异常之前捕获更特定的异常(就像Java一样)。


引用:

MSDN -异常处理 MSDN - try-catch (c#参考)


当前回答

当您没有特定的代码来处理当前异常时,或者当您有处理特定错误情况的逻辑但想要跳过所有其他情况时,通过throw重新抛出异常非常有用。

例子:

string numberText = "";
try
{
    Console.Write("Enter an integer: ");
    numberText = Console.ReadLine();
    var result = int.Parse(numberText);

    Console.WriteLine("You entered {0}", result);
}
catch (FormatException)
{
    if (numberText.ToLowerInvariant() == "nothing")
    {
        Console.WriteLine("Please, please don't be lazy and enter a valid number next time.");
    }
    else
    {
        throw;
    }
}    
finally
{
    Console.WriteLine("Freed some resources.");
}
Console.ReadKey();

然而,还有另一种方法,在catch块中使用条件子句:

string numberText = "";
try
{
    Console.Write("Enter an integer: ");
    numberText = Console.ReadLine();
    var result = int.Parse(numberText);

    Console.WriteLine("You entered {0}", result);
}
catch (FormatException) when (numberText.ToLowerInvariant() == "nothing")
{
    Console.WriteLine("Please, please don't be lazy and enter a valid number next time.");
}    
finally
{
    Console.WriteLine("Freed some resources.");
}
Console.ReadKey();

这种机制比重新抛出异常更有效,因为 的。net运行时不需要重新构建异常对象 然后再扔出去。

其他回答

这取决于您在catch块中所做的事情,以及您是否希望将错误传递给调用代码。

你可能会说Catch io。FileNotFoundExeption ex,然后使用替代文件路径或类似的,但仍然抛出错误。

同样,使用Throw而不是Throw Ex可以让你保持完整的堆栈跟踪。Throw ex从Throw语句重新启动堆栈跟踪(我希望这有意义)。

人们没有提到的一点是,虽然。net语言并没有真正做出适当的区分,但当异常发生时是否应该采取行动,以及是否会解决它,实际上是两个不同的问题。在许多情况下,应该根据无法解决的异常采取行动,在某些情况下,“解决”异常所必需的只是将堆栈展开到某个点——不需要进一步的行动。

Because of the common wisdom that one should only "catch" things one can "handle", a lot of code which should take action when exceptions occur, doesn't. For example, a lot of code will acquire a lock, put the guarded object "temporarily" into a state which violates its invariants, then put it object into a legitimate state, and then release the lock back before anyone else can see the object. If an exception occurs while the object is in a dangerously-invalid state, common practice is to release the lock with the object still in that state. A much better pattern would be to have an exception that occurs while the object is in a "dangerous" condition expressly invalidate the lock so any future attempt to acquire it will immediately fail. Consistent use of such a pattern would greatly improve the safety of so-called "Pokemon" exception handling, which IMHO gets a bad reputation primarily because of code which allows exceptions to percolate up without taking appropriate action first.

In most .NET languages, the only way for code to take action based upon an exception is to catch it (even though it knows it's not going to resolve the exception), perform the action in question and then re-throw). Another possible approach if code doesn't care about what exception is thrown is to use an ok flag with a try/finally block; set the ok flag to false before the block, and to true before the block exits, and before any return that's within the block. Then, within finally, assume that if ok isn't set, an exception must have occurred. Such an approach is semantically better than a catch/throw, but is ugly and is less maintainable than it should be.

不要这样做,

try 
{
...
}
catch(Exception ex)
{
   throw ex;
}

您将丢失堆栈跟踪信息…

无论做什么,

try { ... }
catch { throw; }

OR

try { ... }
catch (Exception ex)
{
    throw new Exception("My Custom Error Message", ex);
}

您可能想要重新抛出的原因之一是,如果您正在处理不同的异常,对于 如。

try
{
   ...
}
catch(SQLException sex)
{
   //Do Custom Logging 
   //Don't throw exception - swallow it here
}
catch(OtherException oex)
{
   //Do something else
   throw new WrappedException("Other Exception occured");
}
catch
{
   System.Diagnostics.Debug.WriteLine("Eeep! an error, not to worry, will be handled higher up the call stack");
   throw; //Chuck everything else back up the stack
}

当您没有特定的代码来处理当前异常时,或者当您有处理特定错误情况的逻辑但想要跳过所有其他情况时,通过throw重新抛出异常非常有用。

例子:

string numberText = "";
try
{
    Console.Write("Enter an integer: ");
    numberText = Console.ReadLine();
    var result = int.Parse(numberText);

    Console.WriteLine("You entered {0}", result);
}
catch (FormatException)
{
    if (numberText.ToLowerInvariant() == "nothing")
    {
        Console.WriteLine("Please, please don't be lazy and enter a valid number next time.");
    }
    else
    {
        throw;
    }
}    
finally
{
    Console.WriteLine("Freed some resources.");
}
Console.ReadKey();

然而,还有另一种方法,在catch块中使用条件子句:

string numberText = "";
try
{
    Console.Write("Enter an integer: ");
    numberText = Console.ReadLine();
    var result = int.Parse(numberText);

    Console.WriteLine("You entered {0}", result);
}
catch (FormatException) when (numberText.ToLowerInvariant() == "nothing")
{
    Console.WriteLine("Please, please don't be lazy and enter a valid number next time.");
}    
finally
{
    Console.WriteLine("Freed some resources.");
}
Console.ReadKey();

这种机制比重新抛出异常更有效,因为 的。net运行时不需要重新构建异常对象 然后再扔出去。

在你发布的代码中的例子中,事实上,捕捉异常没有任何意义,因为在捕捉上没有做任何事情,它只是重新抛出,事实上它弊大于利,因为调用堆栈丢失了。

但是,您可以捕获异常来执行一些逻辑(例如关闭文件锁的sql连接,或者只是一些日志记录),在发生异常时将其扔回调用代码来处理。这在业务层中比在前端代码中更常见,因为您可能希望实现业务层的编码器处理异常。

在你发布的例子中,捕捉异常是没有意义的。不要那样做!