【发布时间】:2010-02-25 20:12:12
【问题描述】:
我知道您不应该编写像这样缓存所有异常类型的代码。
try
{
//code that can throw an exception
}
catch
{
//what? I don't see no
}
相反,您应该做一些更像下面的代码的事情,允许任何其他您没想到会冒泡的异常。
try
{
//code that can throw an exception
}
catch(TypeAException)
{
//TypeA specific code
}
catch(TypeBException)
{
//TypeB specific code
}
但是,如果您用另一个异常包装它们,是否可以捕获所有异常类型?
考虑下面这个Save() 方法,我正在编写作为目录类的一部分。我捕获所有异常类型并返回单个自定义 CatalogIOException 并将原始异常作为内部异常有什么问题吗?
基本上,我不希望任何调用代码必须知道有关 Save() 方法内部可能引发的所有特定异常的任何信息。他们只需要知道他们是否尝试保存只读目录 (CatalogReadOnlyException)、无法序列化目录 (CatalogSerializationException) 或写入文件是否有问题 (CatalogIOException)。
这是处理异常的好方法还是坏方法?
/// <summary>
/// Saves the catalog
/// </summary>
/// <exception cref="CatalogReadOnlyException"></exception>
/// <exception cref="CatalogIOException"></exception>
/// <exception cref="CatalogSerializingExeption"></exception>
public void Save()
{
if (!this.ReadOnly)
{
try
{
System.Xml.Serialization.XmlSerializer serializer = new XmlSerializer(typeof(Catalog));
this._catfileStream.SetLength(0); //clears the file stream
serializer.Serialize(this._catfileStream, this);
}
catch (InvalidOperationException exp)
{
throw new CatalogSerializationException("There was a problem serializing the catalog", exp);
}
catch (Exception exp)
{
throw new CatalogIOException("There was a problem accessing the catalog file", exp);
}
}
else
{
throw new CatalogReadOnlyException();
}
}
更新 1
感谢您迄今为止的所有回复。听起来共识是我不应该这样做,而且我应该只在我确实与它们有关的情况下捕捉异常。在这个 Save() 方法的情况下,确实没有任何我想在 Save() 方法本身中处理的异常。大多数情况下,我只是想通知用户他们无法保存的原因。
我认为我真正的问题是我使用异常作为通知用户问题的一种方式,我让这告诉我如何创建和处理异常有点过多。因此,听起来最好不要捕获任何异常并让 UI 层弄清楚如何通知用户,或者崩溃。这个对吗?考虑下面的 Save Menu 事件处理程序。
private void saveCatalogToolStripMenuItem_Click(object sender, EventArgs e)
{
//Check if the catalog is read only
if (this.Catalog.ReadOnly)
{
MessageBox.Show("The currently opened catalog is readonly and can not be saved");
return;
}
//attempts to save
try
{
//Save method doesn't catch anything it can't deal with directly
this.Catalog.Save();
}
catch (System.IO.FileNotFoundException)
{
MessageBox.Show("The catalog file could not be found");
}
catch (InvalidOperationException exp)
{
MessageBox.Show("There was a problem serializing the catalog for saving: " + exp.Message);
}
catch (System.IO.IOException exp)
{
MessageBox.Show("There was a problem accessing the catalog file: " + exp.Message);
}
catch (Exception exp)
{
MessageBox.Show("There was a problem saving the catalog:" + exp.Message);
}
}
更新 2
还有一件事。如果 Save() 方法是公共 API 与内部代码的一部分,答案会完全改变吗?例如,如果它是公共 API 的一部分,那么我必须找出并记录 Save() 可能抛出的所有可能异常。如果知道 Save() 只能抛出我的三个自定义异常之一,这将容易得多。
此外,如果 Save() 是公共 API 的一部分,安全性是否也不是问题?也许我想让 API 的使用者知道保存不成功,但我不想通过让他们获取可能已生成的异常来公开有关 Save() 工作原理的任何信息。
【问题讨论】:
-
使用您的更新是一种同样有效的方法来处理它,但是您已将消费者转移到比您的原始模型负责更多潜在错误案例,尽管在这种情况下只有 1 个更具体。
-
我认为大多数论点都反对你的最后一项 catch(Exception) 而不是包装其余的。因此,从这个意义上说,您会将 FileNotFound、InvalidOp 等异常保留在较低层(并包装)。建议只是不应该包括您的最终捕获(异常),因为它确实是一个异常,而您已经计划了其他可能性。
-
@Eric - 更新了我的回复 - 看看你的想法。
标签: c# .net exception-handling