C# 在哪里实现try-catch块?
我总是挣扎着在哪里放置试抓挡块。例如,我有一个数据库类,其方法接受两个参数。FindObject(字符串,其中,字符串顺序)。此方法使用指定的where和order字符串执行sql查询 在一个类中,我有一个名为IsUsed的属性,该属性如下所示:C# 在哪里实现try-catch块?,c#,error-handling,C#,Error Handling,我总是挣扎着在哪里放置试抓挡块。例如,我有一个数据库类,其方法接受两个参数。FindObject(字符串,其中,字符串顺序)。此方法使用指定的where和order字符串执行sql查询 在一个类中,我有一个名为IsUsed的属性,该属性如下所示: public bool IsUsed { get { ClassA a = new ClassA(); Collection<ClassA> myCollection = a.FindObject("Id =
public bool IsUsed
{
get
{
ClassA a = new ClassA();
Collection<ClassA> myCollection = a.FindObject("Id = 1","");
if(..) // etc
}
}
public bool IsUsed
{
get
{
ClassA a = new ClassA();
Collection<ClassA> myCollection;
try
{
myCollection = a.FindObject("Id = 1","");
}
catch (SqlServerTimedOutException ex)
{
throw new MyApplicationException("Cannot evaluate if is in use.", ex);
}
if(..) // etc
}
}
使用公共bool
{
得到
{
ClassA=新ClassA();
Collection myCollection=a.FindObject(“Id=1”,”);
if(…)//等
}
}
不管这种方法是否聪明,我只想知道在sql查询执行出错时,在哪里放置try-catch
我应该在哪里放置try catch,以便通知用户出了什么问题
我尝试遵循一个相当简单的规则:如果我能以合理的方式处理异常,我将设置一个try..catch块。如果对于异常我无能为力,我就让它冒泡到调用代码中
作为补充说明,我将避免在属性getter中执行(可能很长的)数据库调用。我通常尝试只设置属性或从备份字段获取值,让其他方法执行数据库查找等。这将使编写调用代码的人更容易预测代码(属性访问通常是一种廉价操作,而方法调用通常更昂贵)。您应该将try cacth块放在可以对捕获的异常执行有意义的操作的位置。就像您记录它或向用户显示它一样。不要仅仅为了捕获异常而捕获异常。好的,它应该是需要try..catch块的地方,以及可以处理它的地方。我假设这将出现在这里的
FindObject
方法中
因此,在FindObject方法中,捕获并处理
SqlException
。如果需要将它移动到更高的级别以更好地处理,那么抛出异常,或者让它冒泡出来。我能想到的唯一规则是“在最低级别,您可以实际使用信息做一些有用的事情,并且不复制异常处理代码”
例如,如果您通常希望以相同的方式捕获所有与数据库访问相关的异常,我将创建一个数据抽象层(有很多很好的理由这样做),并将try-catch块放在那里
另一个极端是web应用程序,您不希望出现任何此类异常,而异常由Elmah捕获。在这种情况下,您根本不想使用try-catch块,因为它会破坏日志记录 这很容易回答:你可以在哪里适当地处理它 也就是说,在给定的地点,你能根据捕获量做出有用的决定吗?你能退点别的吗?你能告诉别人一些事情吗?你能把这个错误转化成一个更有用的错误到你的应用程序的其他层吗 如果答案是肯定的,那么你就在那里抓住了它。如果对所有这些都是否定的,那么就不要抓住它,让另一个地区这样做
FWIW,IMHO,您的
Get
实现也过于复杂。我认为,通常情况下,人们不会期望一处房产做那种“工作”。不过,这只是我的意见。就我而言,我把try-catch块放在了下面:
- 当需要最终清理资源时
- 当出现故障时需要特定的操作流程时(用户重试、记录…)
否则,当我特别懒惰时,我会将Application.ThreadException事件挂接到MessageBox.Show中的static void Main()入口点方法。请参见,如果您遇到任何错误,请将其设置为默认值。大概是这样的:
public bool IsUsed
{
get
{
try{
ClassA a = new ClassA();
Collection<ClassA> myCollection = a.FindObject("Id = 1","");
if(..) // etc
}
catch { return false;}
}
}
使用公共bool
{
得到
{
试一试{
ClassA=新ClassA();
Collection myCollection=a.FindObject(“Id=1”,”);
if(…)//等
}
catch{return false;}
}
}
因此,每当FindObject中出现任何错误时,都会生成false 一般来说,作为一个:
try块包含可能导致异常的受保护代码
在您的案例中,您可以通过以下方式进行内部处理:
FindObject()
{
try{}catch{throw;//or throw new Exception("Some info");
}
IsUser
{
try{...a.FindObject("Id = 1",""); return true;}
catch(Exception ex){Log(ex); return false;}
}
--编辑--
这是对@controlbreak注释的回应:
说:
可以使用throw语句显式抛出异常。还可以使用throw语句再次抛出捕获的异常向重新抛出的异常添加信息是一种很好的编码实践,以便在调试时提供更多信息
这取决于您要在哪里处理和继续处理。假设调用代码负责通知用户,那么调用代码就是一个好地方。调用代码可能需要在通知用户后向用户询问其他问题
也考虑重新设置抛出的异常。如果
IsUsed
驻留在与数据库无关的类中,并且FindObject
可以抛出SqlServerTimedOutException
,它将弹出整个调用堆栈。如果此模式完全混乱,请捕获异常并按如下方式重新调用它:
public bool IsUsed
{
get
{
ClassA a = new ClassA();
Collection<ClassA> myCollection = a.FindObject("Id = 1","");
if(..) // etc
}
}
public bool IsUsed
{
get
{
ClassA a = new ClassA();
Collection<ClassA> myCollection;
try
{
myCollection = a.FindObject("Id = 1","");
}
catch (SqlServerTimedOutException ex)
{
throw new MyApplicationException("Cannot evaluate if is in use.", ex);
}
if(..) // etc
}
}
使用公共bool
{
得到
{
ClassA=新ClassA();
采集;采集;
尝试
{
myCollection=a.FindObject(“Id=1”,”);
}
捕获(SqlServerTimedOutException ex)
{
抛出新的MyApplicationException(“无法评估是否正在使用。”,ex);
}
如果