[英]What are best practices for handling exceptions in C#?
I have following code in my web page: 我的网页中有以下代码:
btnTest_Click(object sender, EventArgs e)
{
...
bool ret=myFunc(...);
if (ret)
{...}
else
{
lblStatus.Text="Some Text";
lblStatus.Visible=true;
}
}
private bool myFunc(...)
{
bool ret=false;
try
{
...
ret=true;
}
catch (Exception ex)
{
lblStatus.Text="Other Text";
lblStatus.Visible=true;
}
return ret;
}
If an exception occurs in myFunc, the lblStatus always shows "Some Text" not "Other Text". 如果myFunc中发生异常,则lblStatus始终显示“某些文本”而不是“其他文本”。 That means the catch block in myFunc doesn't really mean anything. 这意味着myFunc中的catch块实际上没有任何意义。 I wonder how to fix this code to handle the exception better? 我想知道如何修复此代码以更好地处理异常?
update: maybe my example is not very good. 更新:也许我的榜样不是很好。 But I main purpose is to ask best practices for exceptions handling between calling and being called functions. 但是我的主要目的是询问最佳实践,以了解调用和被调用函数之间的异常处理。
Why is your called function setting the label text on exception and the caller setting it on success? 为什么您的被调用函数将标签文本设置为异常,而调用方将其设置为成功?
That's something of a mixed metaphor. 那是一个混杂的隐喻。 Let one party be responsible for UI (separation of concerns) while the other is responsible for doing work. 让一方负责UI(关注点分离),而另一方负责工作。 If you want your called function to be fault tolerant try something like this: 如果希望被调用的函数具有容错能力,请尝试以下操作:
private bool myFunc(...)
{
bool ret ;
try
{
...
ret=true;
}
catch
{
ret = false ;
}
return ret;
}
Then your caller can do something like: 然后,您的呼叫者可以执行以下操作:
bool success = myFunc(...) ;
lblStatus.Text = success ? "Some Text" : "Other Text" ;
lblStatus.Visible = success ;
if ( success )
{
// do something useful
}
It displays "Some Text" because, when an exception occurs in myFunc
, it returns false. 它显示“ Some Text”,因为当myFunc
发生异常时,它返回false。 Then you go into the else
block of the btnTest_Click
method, where you set lblStatus.Text
to "Some Text" again. 然后进入btnTest_Click
方法的else
块,在此处将lblStatus.Text
再次设置为“ Some Text”。
So, basically, you're setting the label's text to "Other text" and then to "Some Text". 因此,基本上,您将标签的文本设置为“其他文本”,然后设置为“某些文本”。
Your catch
clause is doing a lot. 您的catch
子句正在做很多事情。 It catches every exception and "forgets it" suppressing it to the rest of the call stack. 它捕获每个异常并“忘记”异常,将其抑制到调用堆栈的其余部分。 This can be perfectly fine but i'll try to explain your options: 可以很好地解决问题,但我将尝试说明您的选择:
You usually have 3 options: 您通常有3个选择:
I use all of them. 我全部使用。
Option 1 选项1
You can just implement your function and if an exception occurs then it means some fault occurred and you just want your application to fail (at least to a certain level) 您可以只实现您的功能,如果发生异常,则意味着发生了一些错误,并且您只是希望您的应用程序失败(至少到一定程度)
Option 2 选项2
Some exception occurs and you'll want to do one of two (or even both) 发生某些异常,您需要执行两个(或什至两个)之一
Option 3 The exception is expected and you know how to completely react to it. 选项3该异常是预料之中的,您知道如何完全对其进行反应。 For instance, in your case, i tend to believe you do not care about the type of exception but want a "good default" by setting some controls to a given text. 例如,在您的情况下,我倾向于认为您不在乎异常的类型,而是希望通过对给定的文本设置一些控件来实现“良好的默认设置”。
conclusion 结论
There are no silver bullets. 没有银弹。 Use the best option for each scenario. 为每种情况使用最佳选项。 Nevertheless catching and "suppressing" catch(Exception ex)
is rare and if seen often it usually means bad programming. 然而,捕获和“抑制” catch(Exception ex)
很少见,如果经常看到,通常意味着不好的编程。
The exception handling is just fine. 异常处理就可以了。 The problem with your code is that you are putting the "Some Text"
string in the label if the return value is false
, and that is when there was an exception, so it will replace the message from the catch
block. 代码的问题是,如果返回值为false
,那就是在出现异常的情况下,将"Some Text"
字符串放入标签中,因此它将替换catch
块中的消息。
Switch the cases: 切换案例:
if (ret) {
// it went well, so set the text
lblStatus.Text="Some Text";
lblStatus.Visible=true;
} else {
// an exception occured, so keep the text set by the catch block
}
This is a complex question so I will try to break it down 这是一个复杂的问题,所以我将尝试将其分解
null
before attempting to use it (which would throw an exception). 例如,最好在尝试使用变量之前将其测试为null
(这将引发异常)。 Exceptions can be slow (especially if a lot are thrown) 异常可能很慢(尤其是抛出很多异常时) myFunc
were to access a remote server and return a status of true or false you'd expect it to handle its own IO exception. 如果myFunc
要访问远程服务器并返回true或false状态,则希望它能够处理自己的IO异常。 It would probably not handle (or rethrow) any parameter problems. 它可能不会处理(或重新抛出)任何参数问题。 This relates to point 1. It is the functions responsibility deal with the connection process, not to provide the correct parameters. 这与第1点有关。功能职责是处理连接过程,而不是提供正确的参数。 Hiding certain exceptions can cause problems if other people (or a forgetful you) tries to use the code at a later date. 如果其他人(或健忘的人)以后尝试使用该代码,则隐藏某些异常可能会导致问题。 For example in this myFunc
which makes a connection, should you hide parameter exceptions you may not realise you have passed in bad parameters 例如,在建立连接的myFunc
中,如果您隐藏参数异常,则可能不会意识到自己传递了错误的参数 If you want to be informed of encountering a specific type of error inside one of your functions, I'd recommend inheriting Exception and creating your own exception class. 如果要通知您在其中一个函数中遇到特定类型的错误,建议您继承Exception并创建自己的异常类。 I'd put a try-catch block inside your btnTest_Click() handler, and then I'd look to catch your custom exception class. 我会在btnTest_Click()处理程序中放入try-catch块,然后查找您的自定义异常类。 That way, you won't lose the opportunity to detect any errors happening inside your myFunc() function. 这样,您将不会失去检测myFunc()函数内部发生的任何错误的机会。
I usually setup an error handling system. 我通常会设置一个错误处理系统。 Here's a simple way, but this can be wrapped up into a base class. 这是一个简单的方法,但是可以将其包装为一个基类。 I can show you that if you need. 如果需要的话,我可以告诉你。
List<string> _errors;
void init()
{
_errors = new List<string>();
}
protected void Page_Load(object sender, EventArgs e)
{
init();
}
btnTest_Click(object sender, EventArgs e)
{
...
var result = myFunc(...);
if (result)
{...}
else
{
if (_errors.Count > 0)
{
var sb = new StringBuilder("<ul>");
foreach (string err in _errors)
{
sb.AppendLine(string.Format("<li>{0}</li>", err));
}
sb.AppendLine("</ul>");
lblStatus.Text=sb.ToString();//Make this a Literal
}
}
}
private bool myFunc(...)
{
var result = true;
try
{
...
...
}
catch (Exception ex)
{
result = false;
_errors.Add(ex.Message);
}
return result;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.