我正在看关于可序列化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#参考)


当前回答

大多数答案都是关于catch-log-rethrow的。

与其在代码中编写它,不如考虑使用AOP,特别是带有OnExceptionOptions IncludeParameterValue和 IncludeThisArgument

其他回答

c#(在c# 6之前)不支持CIL“过滤异常”,而VB支持,因此在c# 1-5中,重新抛出异常的一个原因是在catch()时没有足够的信息来确定是否要真正捕获异常。

例如,在VB中你可以做到

Try
 ..
Catch Ex As MyException When Ex.ErrorCode = 123
 .. 
End Try

...它不会处理具有不同ErrorCode值的myexception。在v6之前的c#中,如果ErrorCode不是123,你必须捕获并重新抛出MyException:

try 
{
   ...
}
catch(MyException ex)
{
    if (ex.ErrorCode != 123) throw;
    ...
}

从c# 6.0开始,你可以像VB一样过滤:

try 
{
  // Do stuff
} 
catch (Exception e) when (e.ErrorCode == 123456) // filter
{
  // Handle, other exceptions will be left alone and bubble up
}

重新抛出异常的一个有效原因可能是您想要向异常添加信息,或者可能将原始异常包装在您自己制作的异常中:

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) {
    string message = 
      String.Format("Something went wrong serializing DTO {0}", DTO);
    throw new MyLibraryException(message, ex);
  }
}

我使用如下代码的主要原因:

try
{
    //Some code
}
catch (Exception e)
{
    throw;
}

是我可以在catch中有一个断点,它有一个实例化的异常对象。在开发/调试时,我经常这样做。当然,编译器会对所有未使用的e给出警告,理想情况下,应该在发布版本之前删除它们。

不过,在调试过程中它们很好用。

当您没有特定的代码来处理当前异常时,或者当您有处理特定错误情况的逻辑但想要跳过所有其他情况时,通过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运行时不需要重新构建异常对象 然后再扔出去。

首先,本文中代码的实现方式是邪恶的。Throw ex将重置异常中的调用堆栈,直到该Throw语句丢失有关异常实际创建位置的信息。

其次,如果你只是像那样接住然后再扔,我认为没有额外的价值。上面的代码示例如果没有try-catch也一样好(或者,考虑到throw ex位,甚至更好)。

但是,在某些情况下,您可能希望捕获并重新抛出异常。日志可能是其中之一:

    try 
    {
        // code that may throw exceptions    
    }
    catch(Exception ex) 
    {
        // add error logging here
        throw;
    }