Что вернуть? Строка ошибки, Bool с ошибкой String Out или Void с исключением - PullRequest
2 голосов
/ 07 апреля 2010

Я провожу большую часть своего времени в 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.

Мысли

Есть ли другой способ сделать это, о котором я не думаю?

Ответы [ 3 ]

6 голосов
/ 07 апреля 2010

Не существует «одного размера для всех». Если вы вернете флаг, это облегчит использование метода в if() и цикле. Исключения всегда требуют большого количества кода котельной плиты. Если вы просто хотите получить строку, которую вы можете отобразить пользователю (скажем, в веб-интерфейсе), возвращение строки ошибки (или null для «без ошибок») тоже хорошо.

Но большую часть времени я выбрасываю исключение (а в Java подкласс RuntimeException), потому что это позволяет мне возвращать более одной информации об ошибке (например: какой файл вызвал ошибку? Какая строка / колонка? Что я делал? Какое поле в форме должно быть помечено как недопустимое? и т. д.).

В вашем случае вы не можете обработать исключение в вашем методе, поэтому вы не должны его перехватывать. Поймай это только тогда, когда сможешь что-то с этим сделать.

3 голосов
/ 07 апреля 2010

В этом примере, я согласен, вы должны позволить исключению перетекать к потребителю. Однако в качестве альтернативы выбранным вами подходам рассмотрите этот подход.

Вы можете использовать объект ответа для хранения информации, получаемой при запуске метода, например:

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 голосов
/ 07 апреля 2010

Не обрабатывайте исключение и не возвращайте сообщения любого рода. Пусть потребитель вашего метода позаботится об этом.

...