我将大部分时间都花在C#上,并试图找出处理异常的最佳实践,并将调用方法中的错误消息干净地返回给调用方法。
例如,这是一些ActiveDirectory身份验证代码。 请将此方法想象为类的一部分(而不仅仅是一个独立的函数。)
bool IsUserAuthenticated(string domain, string user, string pass, out errStr)
{
bool authentic = false;
try
{
// Instantiate Directory Entry object
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain, user, pass);
// Force connection over network to authenticate
object nativeObject = entry.NativeObject;
// No exception thrown? We must be good, then.
authentic = true;
}
catch (Exception e) { errStr = e.Message().ToString(); }
return authentic;
}
这样做的好处是明确的YES或NO,您可以将其嵌入到If-Then-Else语句中。缺点是它还需要使用该方法的人提供字符串以获取错误(如果有的话)。
我想我可以使用相同的参数减去“out errStr”来重载此方法,但忽略错误似乎是一个坏主意,因为这样的失败可能有很多原因......
或者,我可以编写一个返回错误字符串的方法(而不是使用“out errStr”),其中返回的空字符串表示用户认证正常。
string AuthenticateUser(string domain, string user, string pass)
{
string errStr = "";
try
{
// Instantiate Directory Entry object
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain, user, pass);
// Force connection over network to authenticate
object nativeObject = entry.NativeObject;
}
catch (Exception e) { errStr = e.Message().ToString(); }
return errStr;
}
但这似乎是一种“弱”的做事方式。
或者我应该让我的方法“无效”并且不处理异常以便它被传递回调用函数?
void AuthenticateUser(string domain, string user, string pass)
{
// Instantiate Directory Entry object
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain, user, pass);
// Force connection over network to authenticate
object nativeObject = entry.NativeObject;
}
这似乎对我来说最明白(出于某种原因)。但与此同时,将这两行包装在我需要进行身份验证的每个地方输入2行的唯一真正优势是我不需要包含“LDAP://”字符串。这种方式的缺点是用户必须将此方法放在try-catch块中。
思想?
有没有其他方法可以做到这一点,我没想到?
答案 0 :(得分:6)
没有“一刀切”。如果您返回一个标志,那么可以很容易地使用if()
中的方法并循环。例外总是需要很多锅炉板代码。如果您只想要一个可以向用户显示的字符串(例如,在Web UI中),则返回错误字符串(或null
为“无错误”)也是好的。
但是大多数时候,我抛出异常(在Java中是RuntimeException
的子类)因为这允许我返回多个关于错误的信息(例如:哪个文件导致了错误? line / column?我在做什么?表单中的哪个字段应该被标记为非法?等等。)
在您的情况下,您无法在方法中处理异常,因此您不应该捕获它。只有在你可以采取行动时才抓住它。
答案 1 :(得分:3)
在这个例子中,我同意,你应该让异常流向消费者。但是,作为您突出显示的方法的替代方法,请考虑这种方法。
您可以使用响应对象来保存方法运行中出现的信息,例如:
public abstract class BaseResponse
{
public bool IsOk { get; protected set;}
public string Message { get; protected set; }
}
public class AuthenticationResponse: BaseResponse
{
public AuthenticationResponse(bool isOk): this(isOk, "") {}
public AuthenticationResponse(bool isOk, string message)
{
IsOk = isOk;
Message = message;
}
}
AuthenticationResponse IsUserAuthenticated(string domain, string user, string pass)
{
bool authentic = false;
string errStr;
try
{
// Instantiate Directory Entry object
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain, user, pass);
// Force connection over network to authenticate
object nativeObject = entry.NativeObject;
// No exception thrown? We must be good, then.
authentic = true;
}
catch (Exception e) { errStr = e.Message().ToString(); }
return new AuthenticationResponse(authentic, errStr);
}
然后在if语句中使用它:
AuthenticationResponse response;
if((response = IsUserAuthenticated("domain", "user", "pass")).IsOk)
{
// do successful activity
} else {
Console.WriteLine(response.Message)
}
技巧是赋值操作的返回值是指定的值。因此,我们可以在同一行中进行分配和有效检查。如果您不需要保留调用的结果,则只需调用该方法并检查IsOk属性。
if(IsUserAuthenticated("domain", "user", "pass").IsOk)
{
// do successful activity
}
然后,您可以构建自定义响应对象,以根据需要返回方法中的任意值组合。
答案 2 :(得分:2)
不处理异常或返回任何类型的消息。让您方法的消费者负责这一点。