2012-01-19 204 views
12

我試圖使用Try Catch塊和更好的錯誤處理來提高我的技能。從方法中返回多個結果

我有一個類執行一個共同的任務,在這種情況下,檢索一個Facebook的AccessToken。如果成功,我想返回AccessToken字符串,如果不是,我想返回一條錯誤消息。這些都是字符串,所以沒問題。但是當在代碼的調用方檢查返回值時,如何有效地做到這一點?

這就像我需要返回2個值。在嘗試成功的情況下,返回= true,「ACESSCODEACXDJGKEIDJ」,或者如果失敗,則返回= false,「Ooops,出現錯誤」+ ex.ToString();

然後檢查返回值很容易(理論上)。我可以考慮簡單地返回true/false,然後爲字符串設置Session變量。

什麼是從方法返回多個結果的方法?

回答

21

創建一個結果類,並返回,而不是...

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 
} 
+0

也可以使其通用於任何結果類型,而不是ju st'AccessToken' – Alexander

1

我不會返回錯誤消息。返回一個有意義的值或錯誤並讓它冒泡。你如何處理錯誤取決於你,但至少我會優雅地在前端處理它,並在後端記錄/通知某人。

如果你堅持,即使返回的東西時,你的功能出現了錯誤,那麼我會返回具有以下成員的對象:

Value - String 
Success - Bool 

然後你可以檢查成效,並相應辦理值。

3

一個很好的方法是返回一個包含成功/失敗狀態和詳細錯誤消息的對象。

是這樣的:

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

2可能性彈簧介意

  1. 使用TryXXX圖案(在某些BCL方法如DateTime.TryParse使用)。
  2. 設計一個包含操作狀態和結果的類,然後讓你的方法返回這個類。

我們先來看看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 
} 

結果當然可以是任何其它複雜的對象,而不是(如在該示例中示出)的字符串。

0

你爲什麼不創建一個具有3個屬性的類。成功(布爾),消息(字符串)和令牌(字符串)。您可以創建該類的實例,填充值並返回該值。

0

如果你想返回2個對象,你可以做這樣的事情:

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

     errorMessage = ""; 
     return true; 
    } 

那麼你得到的布爾和錯誤消息

1

使用外部存儲位置(例如會話變量)是錯誤的方式絕對正確。

正確的方法取決於您是否認爲錯誤是異常的情況。如果沒有,那麼用這個詞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 
} 

這裏要注意的重要一點是,這種方式一般使用時,你只關心該操作是否有效(並且你並不在意爲什麼如果失敗則不起作用),並且有合理的預期可能不會。

如果失敗特殊(意思是一個正確配置的程序不應碰到這個錯誤),那麼你應該使用一個例外。事實上,如果你的功能實際上不能實現,那麼你實際上並沒有什麼意義。適當的異常處理意味着讓異常「冒泡」到程序中的任何層,實際上可以對異常做一些有意義和適當的事情。

這也簡化了你的場景,因爲你只需要返回一個字符串。

2

如果成功,我想返回AccessToken字符串,如果不是,我想返回一條錯誤消息。這些都是字符串,所以沒問題。但是當在代碼的調用方檢查返回值時,如何有效地做到這一點?

C#沒有真正使用錯誤消息,我們使用exceptions。做到這一點的正確方法是僅引發異常,並讓調用者忽略或捕獲它。

如果它不是「例外」失敗(例如,如果某些用戶有令牌,而有些用戶沒有令牌),那麼另一種方法是返回一個空字符串來指示缺少令牌(並且仍然拋出「例外」情況例外,例如無法聯繫Facebook等)。我不認爲這是你的情況,因爲你的示例失敗包含一個Exception對象。底線是,您通常將異常處理(捕獲)留給堆棧的頂層(通常是UI),因爲它具有當前操作的最多上下文。捕獲一個異常,重新格式化爲一個字符串,然後返回它是沒有用的 - 在此過程中會丟失寶貴的異常信息。只要讓調用者有例外情況,他們就可以決定如何向用戶展示失敗(或者在沒有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(); 
     } 
    } 
} 
4

嘗試一個元組?

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

要建立在musefan的答案,我想同樣的模式,但與一般的結果類型,所以我可以用它在整個代碼庫:

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.每天都是我希望C#有多個返回值的那一天。

+0

其實它現在有多個返回值。您可以使用Tuple 或Tuple 等。請參閱https://msdn.microsoft.com/en-us/library/dd268536(v=vs.110).aspx – stefann

+0

好吧,多個返回值直接作爲語言構造,本着Lua或Go的精神。 (對不起,不要移動球門柱)。例如: public Thing,string ParseThing(...){...} var thing,err = ParseThing(...); 雖然我還沒有真正想過,我相信,爲什麼它不適合這種語言是有充分的理由的。 – user1454265

+0

我知道你的意思和同意。它可以是Tuple構造之上的語法糖。您應該通過Visual Studio提出建議。 – stefann

2

一個更通用的實現將是

C#

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 

通過這種方法,可以通過在catch塊ex.MessageData<T> try塊