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


当前回答

你不会想要抛出ex -,因为这会丢失调用堆栈。参见异常处理(MSDN)。

是的,尝试…Catch没有做任何有用的事情(除了丢失调用堆栈之外——所以它实际上更糟——除非出于某种原因您不想公开此信息)。

其他回答

抱歉,但许多“改进设计”的例子仍然很糟糕,或者可能会极具误导性。有try {} catch {log;Throw}完全没有意义。异常日志应该在应用程序的中心位置完成。无论如何,异常都会出现在堆栈跟踪中,为什么不将它们记录在系统边界附近的某个地方呢?

Caution should be used when you serialize your context (i.e. DTO in one given example) just into the log message. It can easily contain sensitive information one might not want to reach the hands of all the people who can access the log files. And if you don't add any new information to the exception, I really don't see the point of exception wrapping. Good old Java has some point for that, it requires caller to know what kind of exceptions one should expect then calling the code. Since you don't have this in .NET, wrapping doesn't do any good on at least 80% of the cases I've seen.

人们没有提到的一点是,虽然。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.

当您为库或dll编程函数时,这可能很有用。

此重抛出结构可用于有目的地重置调用堆栈,以便从函数本身获取异常,而不是从函数内部的单个函数中查看抛出的异常。

我认为这样做只是为了让抛出的异常更清晰,并且不会进入库的“根”。

虽然许多其他答案提供了很好的示例,说明为什么您可能希望捕获重抛出异常,但似乎没有人提到“最终”场景。

举个例子,你有一个方法,你在其中设置了游标(例如一个等待游标),该方法有几个出口点(例如if () return;),你想确保游标在方法结束时被重置。

为此,您可以将所有代码包装在try/catch/finally中。在最后将光标设置回右光标。这样就不会隐藏任何有效的异常,在catch中重新抛出它。

try
{
    Cursor.Current = Cursors.WaitCursor;
    // Test something
    if (testResult) return;
    // Do something else
}
catch
{
    throw;
}
finally
{
     Cursor.Current = Cursors.Default;
}

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

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

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

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