我创建了一个从文件中解析某些文档的类。
class Parser
{
public Parse(string fileName)
{
///
}
}
在解析器具有的情况下,有时会出现解析错误 返回某些数据。我为此创建了特殊课程。
class ParsingError
{
// some data
}
我如何正确处理此类错误。我至少有两个选择:
创建我自己的异常或返回值。
选项一
myParser.Parse(fileName, out error);
选项二
try
{
myParser.Parse(fileName)
}
catch(MyParsingException ex)
{
// use ex.Error field
}
更新
如果我没有弄错,那么例外背后的意识形态就是它应该处理一些特殊的事情,那就是该方法不打算处理的一些情况。
这让我想知道是否例如:
解析器在文件中找到未知字段,或者编码错误
会被视为例外吗?
答案 0 :(得分:14)
想一想解析错误的典型程度。如果它是典型的 - 支持返回值。异常应该用于不正常的事情。
答案 1 :(得分:5)
.NET land的异常理念与其他平台略有不同。在.NET领域不需要很长时间才能意识到你不再在OZ中,并且经常会抛出异常。
从.NET 4上的MSDN: 不要返回错误代码。例外是在框架中报告错误的主要方法。
从.NET 4.5上的MSDN: 例外是执行程序遇到的任何错误情况或意外行为。
他们给出的一个例子是客户端无法连接到端点。因此,如果您认为有时网站不可用于网络或其他原因,这不符合传统的“例外”定义,您可以了解他们的创作者如何打算使用例外。
答案 2 :(得分:3)
我会选择三个
ParseResult result = myParser.Parse(filename)
这里ParseResult可以提供有关解析结果的更多细节,包括正面和负面。
如果失败情况非常罕见且会被视为意外结果,那么我会选择你的选项2并抛出异常。当然,最终的解决方案可能是一个组合,在ParseResult中返回常见错误,但是例如无法打开文件等异常情况表现为异常。
答案 3 :(得分:2)
这取决于MyParsingException是否只是来自System.Exeption的派生类,或者它包含有关尝试解析文件时出错的其他信息。如果没有这样的信息,那么我认为Parse方法应该返回一个字符串,如果发生错误则返回null:
public string Parse(string fileName)
{
string res = null;
try
{
/// parse the file, assign parse result to res
}
catch
{
res = null;
}
return res;
}
或者,如果exeption确实有用,则包含有关文件(名称),行号等的信息:
public string Parse(string fileName)
{
string res = null;
int errorLine = -1;
try
{
// foreach line of text to parse -- errorLine = lineNumber;
/// parse the file, assign parse result to res
}
catch (Exeption ex)
{
MyParsingException myEx= new MyParsingException ("parsing error", ex);
myEx.Data["fileName"] = fileName;
myEx.data["lineNumber"] = errorLine ;
throw myEx;
}
return res;
}
// then you can have some really useful info:
try
{
myParser.Parse(fileName)
}
catch(MyParsingException ex)
{
// use ex.Data to get the "fileName" and "lineNumber" properties.
}
答案 4 :(得分:2)
在立即调用者要处理无效条件的情况下,错误标志或返回值通常更好。如果有许多函数调用可能以特定方式失败,并且所有这些函数调用的错误处理应该相同,则异常通常会更好。
方法的作者通常无法知道哪个场景将适用于其调用者(实际上,某些调用者通常更适合一种模式而另一种模式更适合其他模式)。 Microsoft首选的处理方式是使用模式:
Thing GetThing(int param1, string param2);
bool TryGetThing(int param1, string param2, out Thing result);
这肯定是一个比限制调用者适合一种模式或另一种模式更好的概念,尽管我不喜欢特定的实现。 Microsoft明确建议使用单独的方法,而不是使用一个带有参数的方法来指示失败是否应该抛出异常,但这种理念是有代价的:它意味着如果GetThing
或{{TryGetThing
之一的步骤之一1}}可以使用“do”或“try”方法完成,GetThing
和TryGetThing
的代码必须大部分重复,一个调用“do”方法,另一个调用“尝试“方法。
另一种方法是使用委托或接口类型对象,该对象指示发生异常时“try”方法应该执行的操作。例如,可以有一个函数:
Thing TryGetThing(int param1, string param2, bool ThrowOnError, out ErrorInfo errInf);
可能有一个重载,如果省略最后两个参数,将调用上面true
ThrowOnError
和errInf
的虚拟变量。如果TryGetThing
使用的方法遵循类似的模式,则可以调用它们而不必为try / do案例重复代码。
答案 5 :(得分:1)
如果你的API说它处理解析错误,那么这不是一个例外的情况,也许应该返回解析错误。对于其他东西,比如丢失文件,锁定文件,无效输入(除了狡猾的解析),你应该抛出异常。
答案 6 :(得分:0)
对我来说,这取决于我计划如何消耗错误以及它是什么样的错误。该方法的背景也起了作用。如果预计该方法每隔一段时间就会在xml中出现错误,那么它在我眼中并不是一个例外,应该相应地对待。
假设我正在编写XML验证器,然后返回错误是要走的路。如果我正在编写XML配置解析器,则异常似乎更合适。