【问题标题】:What to Return? Error String, Bool with Error String Out, or Void with Exception返回什么?错误字符串、带有错误字符串输出的 Bool 或带有异常的 Void
【发布时间】:2010-04-07 14:38:06
【问题描述】:

我大部分时间都花在 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;
}

这样做的好处是明确的“是”或“否”,您可以将其嵌入到您的 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; 
}

这对我来说似乎是最理智的(出于某种原因)。然而与此同时,将这两行包装起来而不是在我需要验证的任何地方键入这两行的唯一真正优势是我不需要包含“LDAP://”字符串。这样做的缺点是用户必须将此方法放在 try-catch 块中。

想法?

还有其他我没有想到的方法吗?

【问题讨论】:

    标签: exception exception-handling return-value return


    【解决方案1】:

    没有“一刀切”。如果您返回一个标志,则可以很容易地使用 if() 中的方法和循环。异常总是需要大量的样板代码。如果您只想要一个可以显示给用户的字符串(例如,在 Web UI 中),返回错误字符串(或 null 表示“无错误”)也很好。

    但大多数时候,我会抛出异常(在 Java 中是 RuntimeException 的子类),因为这允许我返回多个关于错误的信息(例如:哪个文件导致了错误?哪一行/列?我在做什么?表单中的哪个字段应该被标记为非法?等等)。

    在你的情况下,你不能在你的方法中处理异常,所以你不应该捕获它。只有当你可以做点什么时才能抓住它。

    【讨论】:

      【解决方案2】:

      在这个例子中,我同意,你应该让异常流向消费者。但是,作为您强调的方法的替代方法,请考虑这种方法。

      您可以使用响应对象来保存来自方法运行的信息,例如:

      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
      }
      

      然后,您可以构建您的自定义响应对象,以根据需要从您的方法返回任何值组合。

      【讨论】:

      • +1 -- 哇!这很聪明!即使我了解您在做什么,但我不确定我是否会在实践中实施它。也许我只需要让它在我的大脑中炖一会儿,也许我会适应它...... :-) 谢谢!
      【解决方案3】:

      不要处理异常或返回任何类型的消息。让您的方法的使用者来处理这个问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-08-26
        • 2022-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-03
        • 1970-01-01
        相关资源
        最近更新 更多