C# 我应该把我自己的论点扔出范围例外还是让一个从下面冒出来?
我有一个类包装列表 我使用索引方法获取值:C# 我应该把我自己的论点扔出范围例外还是让一个从下面冒出来?,c#,.net,exception,exception-handling,C#,.net,Exception,Exception Handling,我有一个类包装列表 我使用索引方法获取值: public RenderedImageInfo GetValue(int index) { list[index].LastRetrieved = DateTime.Now; return list[index]; } 如果用户请求的索引超出范围,这将抛出ArgumentOutOfRangeException 我应该让这一切发生还是检查一下,然后扔掉我自己的?i、 e public R
public RenderedImageInfo GetValue(int index)
{
list[index].LastRetrieved = DateTime.Now;
return list[index];
}
如果用户请求的索引超出范围,这将抛出ArgumentOutOfRangeException
我应该让这一切发生还是检查一下,然后扔掉我自己的?i、 e
public RenderedImageInfo GetValue(int index)
{
if (index >= list.Count)
{
throw new ArgumentOutOfRangeException("index");
}
list[index].LastRetrieved = DateTime.Now;
return list[index];
}
在第一个场景中,用户将有一个来自内部列表的异常,这打破了我的OOP目标,即用户不需要知道底层对象
但在第二个场景中,我感觉好像在添加冗余代码
编辑:现在我想起来了,第三种情况怎么样,我捕获内部异常,修改它,然后重新显示它?在这种情况下,让异常冒泡出来是可以的 编辑 我被要求更新我的答案,包括一些回答 可以说,捕获异常并将其作为内部重新引用更为健壮,因为它将您与更改隔离开来,并创建一个更一致的接口。话虽如此,在开发人员可以访问所有代码的环境中,好处可能非常小——几乎没有。此外,我们获得的任何微小利益都不是免费的。额外的错误处理代码增加了复杂性,必须对其本身进行测试以确保其正常工作。它还增加了在维护期间破坏该方法的风险,因为该方法的基本功能可能会被所有防弹措施所掩盖 那么,这值得吗?视情况而定。它归结为成本/收益分析,这只能针对特定的环境进行。对于公共API(如AlphaFS),其好处可能远远超过成本。对于不是为显著重用而设计的代码的内部使用,它可能不是。这就是我最初回答的背景,我仍然支持。此外,正如Hightechrider所指出的,可能还有其他技术,比如编码契约,它们产生了几乎相同的好处,但成本较低,改变了等式,有利于健壮性 和往常一样,我对合理的分歧持开放态度。然而,我建议大家尽量避免一刀切的想法 编辑
为了清楚地表明,当我说错误处理代码容易出错时,我并没有发疯,请看一下原始问题,并告诉我您是否能够发现错误。如果你愿意的话,我会给你一个+1。你应该放弃你自己的,原因有两个:
在本例(ArgumentOutOfRangeException)中,存在内部列表这一事实应作为实现细节保留,用户没有理由查看该信息。如果您使用的是.NET 2.0或更高版本,则可以使用,如下所示:
public RenderedImageInfo GetValue(int index)
{
try {
list[index].LastRetrieved = DateTime.Now;
return list[index];
} catch (ArgumentOutOfRangeException ex) {
throw new ArgumentOutOfRangeException("index", ex);
}
}
这样,您的用户将主要看到您的异常,但如果您(或他们)愿意,可以深入挖掘
编辑:我现在明白了,自从.NET 1.0以来,它就一直受到支持,只是这个构造函数是新的。在2.0之前的.NET中,我看不到为ArgumentOutOfRangeException
实际设置InnerException
的方法。是他们忘记了,还是我上面写的代码违背了预期用途
…打破了用户不需要了解底层对象的m[y]OOP目标
抛出相同的异常对封装没有任何作用。您的(暗示/记录-因为我们没有检查异常或DbC)合同声明,在这种情况下,您是否将抛出ArgumentOutOfRange
异常。异常是如何生成的,以及它的堆栈跟踪与调用方无关
如果您将内部实现移动到不会抛出ArgumentOutOfRange异常的位置,那么您需要自己抛出一个异常来履行合同(或者对合同进行破坏性更改)
堆栈跟踪(和参数名)用于guy调试,而不是用于编程访问。除非出于安全考虑,否则不必担心让它们“泄漏”
顺便说一句,包装异常的建议(您可能正在考虑)来自一个更抽象的场景。考虑如果用户不能<代码>登录,,将引发“<代码> IudioTestService < /代码>”。
如果同时存在LdapAuthenticationService
和DatabaseAuthenticationService
实现,那么您必须捕获LdapDirectoryException
和SqlException
以确定登录失败。当第三个实现完成时,您还需要添加它的特定异常类型。所有实现者都将其特定异常包装在一个FailedAuthenticationException
中,您只需要担心一种类型
不过,在InnerException
中包含原始异常仍然是一个好主意,因为它有助于调试
我希望您能看到这个场景和您的场景之间的区别——在您的例子中,您只是抛出了相同的异常类型,所以没有区别
说了这么多,如果是图书馆的话,我会检查一下然后扔掉。但这并不是为了OOP的纯洁性,而是因为它使契约变得明确,不太可能在无意中被更改。如果我使用的是[T | B]DD,那么我只需要为它编写一个测试,然后让Lis