我想知道,为什么Microsoft开发人员不向我们提供"尝试"各地不可靠的方法版本?
如果我使用数据库连接或smtp客户端,我总是必须考虑例外:
try
{
smtpClient.Send(message);
}
catch (SmtpException)
{
// test with real smtp server and analyze an exception and it's contents here
}
但我想要的是用户:
if(!smtpClient.TrySend(message, out reason))
{
// analyze reason here
}
对我来说最大的问题是异常性能开销。我无法承担在我的服务的每个客户电话上抛出异常。如果我需要检查几十个连接/提供者,这可能会导致每个客户端请求有几十个异常。
我的问题是:.NET中这种API设计决策的基本原理是什么?我不认为这是一个错误,因为它无处不在,而不是单一的技术。
更新
我必须再给你一个.NET异常的例子来停止谈论网络延迟。例如,如果停止Windows服务,System.Diagnostics.EventLog.WriteEntry
方法可以抛出System.ComponentModel.Win32Exception
。
答案 0 :(得分:6)
我想知道,为什么Microsoft开发人员不向我们提供"尝试"各地不可靠的方法版本?
由于我不是微软的员工,我只能猜测。我的猜测是有两个原因:
在设计.NET类库的第一个版本时,他们没有想到它 - 请注意,TryParse
方法已在更高版本中添加。
性能差异不够重要(见下文),以保证实施和维护新Try...
方法的成本。 .NET Framework还需要更紧急的其他内容。
对我来说最大的问题是异常性能开销。
我严重怀疑。 "性能开销"一个SMTP超时(=几秒)占据"performance overhead" of throwing an exception(不到一毫秒)超过1000倍。
答案 1 :(得分:4)
考虑到您正在调用基于网络的服务,抛出异常本身的成本而不是会导致性能下降。找出何时抛出异常是罪魁祸首:系统需要尝试网络调用,等待超时或返回失败,然后才抛出异常。
实际投掷的成本很低,因此提供Try
方法无助于提高性能。但是,它可以帮助您提高可读性,这不是一件小事。为此,您可以编写自己的Try
包装器/扩展方法,并隐藏其中的异常捕获:
public static bool TrySend(this SmtpClient client, object message, out Error reason) {
try {
client.Send(message);
reason = null;
return true;
} catch (SmtpException ex) {
reason = ex.Reason;
return false;
}
}
答案 2 :(得分:4)
好的,你还没有看到异常点。你所建议的(一个尝试...版本的所有东西)基本上完全击败了例外。异常之处在于您不需要检查每个方法调用的结果。你只是假设一切都会成功(常规案例),如果一次调用失败,它将被捕获"并在您的调用堆栈中的预定位置处理。您的代码将更具可读性,因为它只有重要的步骤,而不是管道。尝试......对于更有可能/更常见的情景来说是很好的#34;失败"并不是真正的错误或问题,而只是正常流量控制逻辑的一部分。
异常是OO方式,返回错误代码是旧学校。考虑一个深层嵌套的调用层次结构,并负责处理所有级别的错误代码并适当地处理它们。将其与使用例外进行比较。你看到了光吗? : - 。)
答案 3 :(得分:1)
与您正在执行的发送/数据库操作相比,异常性能开销可以忽略不计。 因此,有些情况(如这些)支持TryParse模式有点不需要。
如果您处于导致“数十个异常”的“数十个连接/提供者”的情况下,可能值得检查它发生的原因,那么您的smtp服务器可能是一个全局问题。
P.S。披露我是微软员工,但即使我在工作中说苹果或谷歌,我也会回答你同样的问题。
答案 4 :(得分:1)
您不经常看到Try
方法的主要原因是异常会传达某些信息。一个特殊的"条件发生,某事必须处理它。您刚刚执行的操作非常重要,失败会导致整个过程关闭。抛出异常的方法无法处理这种情况,抛出异常会强制某些代码块来处理这个问题。
网络调用对于应用程序的成功运行至关重要,大多数情况下,异常是恰当的。此外,异常包含消息和堆栈跟踪,这对于调试故障至关重要。您提出的解决方案会删除关键调试信这并不总是至关重要的,就像解析int一样,特别是当它通常很容易从错误中恢复时。
网络呼叫失败或写入光盘是一个完全不同的野兽。
答案 5 :(得分:1)
这个问题当然是合理的。以Eric Lippert的blog entry on exceptions为基础,并假设你采取了必要的预防措施,以确保发送失败,因为某些网络条件(而不是因为你在某处传递了无效的参数),我会将SmtpException归类为外生的 - 就像文件一样打开,你可能无法阻止它。因此,我不会将SmtpException归类为烦恼,这不是糟糕设计选择的结果(如int.Parse)。
确保SmtpException确实表示异常,异常将是一个合适的工具。与其他人所说的那样,开销可以忽略不计。