Подтвердить что ты не робот

Возвращение нескольких результатов из метода

Я пытаюсь улучшить свои навыки, используя блоки Try Catch и улучшая обработку ошибок.

У меня есть класс, который выполняет общую задачу, в этом случае извлекает Facebook AccessToken. В случае успеха я хочу вернуть строку AccessToken, если я не хочу возвращать сообщение об ошибке. Это обе строки, поэтому проблем нет. Но когда вы проверяете возвращаемое значение на вызывающей стороне кода, как вы можете это сделать эффективно?

Мне нравится возвращать 2 значения. В случае успешной попытки return = true, "ACESSCODEACXDJGKEIDJ", или если это не удается, return = false, "Ooops, была ошибка" + ex.ToString();

Тогда проверка возвращаемого значения легко (теоретически). Я мог бы думать о возвращении просто true/false для возврата, а затем установке переменной Session для строк.

Каков способ возврата нескольких результатов из метода?

4b9b3361

Ответ 1

Создайте класс Result и верните его...

public class Result
{
   public bool Success {get;set;}
   public string AccessToken {get;set;}
   public string ErrorMessage {get;set;}
}


public Result GetFacebookToken()
{
   Result result = new Result();

   try{
      result.AccessToken = "FACEBOOK TOKEN";
      result.Success = true;
   }
   catch(Exception ex){
      result.ErrorMessage = ex.Message;
      result.Success = false;
   }

   return result;
}

Затем вы можете вызвать этот код, как...

Result result = GetFacebookToken();

if(result.Success)
{
   //do something with result.AccessToken
}
else
{
   //do something with result.ErrorMessage 
}

Ответ 2

2 возможности spring для ума

  • Используйте шаблон TryXXX (используемый в некоторых методах BCL, таких как DateTime.TryParse).
  • Создайте класс, который содержит статус операции и результат, а затем верните этот класс в свой метод.

Сначала рассмотрим шаблон TryXXX. Это в основном метод, который возвращает логическое значение и результат как out.

public bool TryXXX(string someInput, out string someResult, out string errorMessage)
{
    ...
}

который будет потребляться следующим образом:

string someResult;
string errorMessage;
if (!TryXXX("some parameter", out someResult, out errorMessage))
{
    // an error occurred => use errorMessage to get more details
}
else
{
    // everything went fine => use the results here
}

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

public class MyResult
{
    public bool Success { get; set; }
    public string ErrorMessage { get; set; }

    public string SomeResult { get; set; }
}

а затем ваш метод возвращает этот класс:

public MyResult MyMethod(string someParameter)
{
    ...
}

который будет потребляться следующим образом:

MyResult result = MyMethod("someParameter");
if (!result.Success)
{
    // an error occurred => use result.ErrorMessage to get more details
}
else
{
    // everything went fine => use the result.SomeResult here
}

Конечно, результатом может быть любой другой сложный объект вместо (как показано в этом примере) строки.

Ответ 3

Чтобы построить ответ musefan, мне нравится тот же шаблон, но с общим типом Result, поэтому я могу использовать его на всей кодовой базе:

public class Result
{
    public bool Success { get; set; }
    public string ErrorMessage { get; set; }
}

public class Result<T> : Result
{
    public T Data;
}

Одна из причин, по которой мне это нравится, или исключение исключения из функции, которая в противном случае возвращает данные, заключается в том, что это помогает вам сопоставить эту функцию над коллекцией, фиксируя детали исключения в сообщениях об ошибках, поэтому вам не нужно беспокоиться о исключение на один предмет, раздувающий всю цепочку. Это полезно для ситуаций, таких как синтаксический анализ строк из плоского файла данных, где успешные строки должны двигаться вперед, но любые ошибки следует обрабатывать индивидуально:

public static Result<Thing> ParseThing(string line)
{
     try 
     {
          // Parse a Thing (or return a parsing error.)
          return new Result<Thing> { Data = thing, Success = true };
     }
     catch (Exception ex)
     {
          return new Result<Thing> { Data = null, Success = false, ErrorMessage = "..." };
     }
}

...

var results = lines.Select(ParseThing);

foreach (var result in results)
{
    // Check result.Success and deal with successes/failures here.
}

Конечно, у вас все еще есть возможность исключить исключение из этой функции для действительно исключительных ситуаций, когда взорвать всю цепочку обработки - это то, что вы хотите.

P.S. Каждый день - это тот день, когда я хочу, чтобы у С# было несколько возвращаемых значений.

Ответ 4

Попробуйте кортеж?

public Tuple<bool, string> ReturnsBoolAndString() {
    return Tuple.Create(false, "string");
}

Ответ 5

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

Что-то вроде:

class Result
{
   bool IsSuccessful { get; set; }
   string DetailedStatus { get; set; }
}

Ответ 6

В случае успеха я хочу вернуть строку AccessToken, если я не хочу возвращать сообщение об ошибке. Это обе строки, поэтому проблем нет. Но когда вы проверяете возвращаемое значение на вызывающей стороне кода, как вы можете это сделать эффективно?

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

Если это не "исключительный" сбой (например, если у некоторых пользователей есть токены, а у некоторых нет), альтернативой было бы вернуть пустую строку, указывающую на отсутствие токена (и все равно выдавать исключение для "исключительных" случаев, таких как невозможность связаться с Facebook и т.д.). Я не думаю, что случай для вас, так как ваш пример отказа включал объект Exception.

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

Это, очевидно, насмехается, но, надеюсь, моя точка зрения (код говорит громче, чем слова):

class Facebook {
   ...
   public string GetAccessToken(string username, string password) {
      // can throw WebException if can't connect to FB
      this.Connect(); 

      // returns null token if not a Facebook user
      if (!this.IsUser(username)) return null;

      // can throw ArgumentException if password is wrong
      var fbInfo = this.GetInfo(username, password);

      return fbInfo.AccessToken;
   }
   ...
}

class Page {
   void Page_Load(object sender, EventArgs e) {
      var fb = new Facebook();

      string accessToken;
      try {
         accessToken = fb.GetAccessToken(this.User.Name, this.txtPassword.Text);
      } catch (WebException ex) {
         Log(ex);
         this.divError.Text = "Sorry, Facebook is down";
         // continue processing without Facebook
      } catch (ArgumentException ex) {
         // Don't log - we don't care
         this.divError.Text = "Your password is invalid";
         // stop processing, let the user correct password
         return;
      } catch (Exception ex) {
         Log(ex);
         // Unknown error. Stop processing and show friendly message
         throw;
      }

      if (!string.IsNullOrEmpty(accessToken)) {
         // enable Facebook integration 
         this.FillFacebookWallPosts(accessToken);
      } else {
         // disable Facebook integration
         this.HideFacebook();
      }
   }
}

Ответ 7

Более общая реализация будет

С#

public class ReturnMessage<T>
{
    //indicates success or failure of the function
    public bool IsSuccess { get; set; }
    //messages(if any)
    public string Message { get; set; }
    //data (if any)
    public T Data { get; set; }
}

VB.NET

Public Class ReturnMessage(Of T)
    'indicates success or failure of the function
    Public Property IsSuccess As Boolean
    'messages(if any)
    Public Property Message As String
    'data (if any)
    Public Property Data As T
End Class

С помощью этого метода можно передать ex.Message в блоке catch и Data<T> в блоке try

Ответ 8

Я не вернул бы сообщение об ошибке. Верните значащее значение или ошибку и дайте ему пузыриться. Как вы справляетесь с ошибкой, зависит от вас, но, как минимум, я бы изящно обрабатывал ее на переднем конце и регистрировал/уведомлял кого-то на сервере.

Если вы настаиваете на возврате чего-либо даже тогда, когда ошибки вашей функции выходят из системы, я возвращаю объект, который имеет следующие элементы:

Value - String
Success - Bool

Затем вы можете проверить успех и обработать значение соответствующим образом.

Ответ 9

Вы определенно правы, что использование внешнего хранилища (например, переменной сеанса) является неправильным способом.

Правильный подход зависит от того, считаете ли вы ошибку исключительным обстоятельством. Если нет, то следуйте примеру, установленному в фреймворке, префикс вашей функции словом Try и его подпись выглядит так:

public bool TryGetFacebookToken(<necessary parameters>, out string token)
{
    ... set the token within the body and return true if it succeeded or false if it did not
}

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

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

Это также упрощает ваш сценарий, так как вам нужно только вернуть строку.

Ответ 10

Почему бы вам не создать класс с 3 свойствами. успех (bool), сообщение (строка) и токен (строка). Вы можете создать экземпляр этого класса, заполнить значения и вернуть их.

Ответ 11

Если вы хотите вернуть 2 объекта, вы можете сделать что-то вроде этого:

    private bool TestThing(out string errorMessage)
    {
        bool error = true;
        if(error)
        {
            errorMessage = "This is a message!";
            return false;
        }

        errorMessage = "";
        return true;
    }

тогда вы получите сообщение bool и сообщение об ошибке