什么归来?错误字符串,错误字符串输出的Bool或具有异常的空字符

时间:2010-04-07 14:38:06

标签: exception exception-handling return-value return

我将大部分时间都花在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块中。

思想?

有没有其他方法可以做到这一点,我没想到?

3 个答案:

答案 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)

不处理异常或返回任何类型的消息。让您方法的消费者负责这一点。