2011-11-02 124 views
3

你用什麼策略來給用戶之所以一定的方法「失敗」如何評價爲什麼一個方法返回它返回什麼

例:

public List<Balance> GetBalanceFinale(Periode periode) 
    { 
     if (periode == null || periode.DateStart >= DateTime.Now || isBalanceFinished(periode.PeriodeID)) 
      return null; 

     //My other code... 
    } 

我想告訴用戶哪個步驟出錯了。我不想在這樣的類中使用消息框。我無法返回失敗的描述,因爲我已經返回了一些東西。

你通常做什麼?有什麼建議?謝謝!

回答

2

我假設你不想拋出異常,否則你已經這樣做了。就像警告/警告而不停止執行程序。在這種情況下,您仍然可以使用異常,只是不要拋出異常,而是將其作爲輸出參數傳遞,或者放在用戶可以根據需要訪問它的地方。如果這看起來超過了頂部,那麼只需使用一條消息。

將它作爲'嘗試'方法也可能是一個好主意。它清楚地表明該方法在某些條件下容易發生故障。

這些都是不同的選擇:

public bool TryGetBalanceFinale(Periode periode, out List<Balance> list, out string msg) 
{ 
    // return false if anything is wrong, and have an out parameter for the result & msg 
} 

public bool TryGetBalanceFinale(Periode periode, out List<Balance> list, out Exception ex) 
{ 
    // return false if anything is wrong, and have an out parameter for the exception 
} 

上述前兩個是我的兩個首選的方法。以下是可能還有,但它們確實有點不標準:

public Tuple<string, bool> TryGetBalanceFinale(Periode periode, out List<Balance> list) 
{ 
    // return false if anything is wrong, and include message in the returned Tuple 
} 


// an anonymous type approach 
public object TryGetBalanceFinale(Periode periode, out List<Balance> list) 
{ 
    return new { 
     Successful = false, 
     Message = // reason why here 
    }; 
} 

// a functional approach 
public List<Balance> list GetBalanceFinale(Periode periode, Action<String> messageAct) 
{ 
    // when something is wrong, do: 
    messageAct("Something went wrong..."); 
} 

我認爲「嘗試」戰略是很有道理的,當你考慮如何將用於:

string message; 
List<Balance> result; 

if (!TryGetBalanceFinale(periode, out result, out message)) 
{ 
    // examine the msg because you know the method failed 
    Console.WriteLine(message); 
} 
else 
{ 
    // you know the method succeeded, so use the result 
    Console.WriteLine("The result is: " + result.ToString()); 
} 
+0

儘管我從不特別喜歡'out'參數,但我認爲這個解決方案非常簡潔! – Mathieu

+0

匿名類型的方法讓我感到非常恐怖。我寧願使用實際類型或「元組」。傳遞如何處理錯誤的「行動」的想法有點奇怪,但在某些情況下非常有效。在很多情況下,人們可以比這更進一步,只是將整個事情包裝在一個班級中。如果你這樣做,你會失敗成爲一個事件。 – Brian

7

您可以使用描述性消息拋出異常。

+2

不例外在這種情況下不必要的性能影響? –

+1

不是一個描述性消息,您可能需要多語言支持。拋出一個自定義異常並設置枚舉。你可以在你的圖形用戶界面上捕捉並解析它。 – DanDan

+1

@GlennFerrieLive,這個問題應該是爭論的例外。如果是這樣,那麼就這樣對待它。在類似於問題的情況下,'ArgumentException'是完全合理的。 –

1

如果我需要返回一個值和一條消息,我只是使用一個out參數。

public List<Balance> GetBalanceFinale(Periode periode, out string errorMessage) 
{ 
    if (periode == null) 
    { 
     errorMessage = "Periode is null"; 
     return null; 
    } 

    // Other checks 
} 

然後就這樣稱呼它

string errorMessage; 
var value = GetBalanceFinale(periode, out errorMessage); 
if(value == null) 
    // Do whatever with errorMessage 
+1

在我看來,它更有意義的是List作爲out參數。這是一個標準的做法,就像.NET中的所有'TryParse'方法等一樣。 –

1

你可以分解你的邏輯爲3次獨立的測試,然後定義一個「出」參數來返回「原因」

public List<Balance> GetBalanceFinale(Periode periode, out string reasonFailed) 
{ 
    reasonFailed = false; 
    if (periode == null) 
    { 
     reasonFailed = "preiod is null"; 
     return null; 
    } 
    // etc..... 
    //periode.DateStart >= DateTime.Now || isBalanceFinished(periode.PeriodeID)) 


    //My other code... 
} 
+0

與布蘭登所說的一樣,我想。領帶去跑步者。 –

+2

如果你認爲你的答案與其他人的答案相同,那麼刪除你的答案(通常是提高另一答案),特別是如果其他答案是首先發布的話。 –

5

考慮拋出異常而不是返回null。

在這種情況下,您將能夠爲每個異常提供描述性信息,以後可以正確處理並提供給調用者。

+3

請勿在您的帖子中使用簽名或標語。 http://stackoverflow.com/faq#signatures – Greg

2

我喜歡將我的結果包裝在ResultState<T>對象中(通常用於Json或Xml序列化)。如果您正在爲別人構建一個框架供消費者使用,可能會有所幫助,因爲每個結果都可以由消費者以相同方式處理。

public class ResultState<T> 
{ 
    public T ResultValue { get; set; } 
    public Exception ExceptionThrown { get; set; } 
    public bool IsValid { get; set; } 
    public string FriendlySummary { get; set; } 
    // whatever else properties you think are needed 
} 

public interface IResultState<T> 
{ 
    public T ResultValue { get; } 
    public Exception ExceptionThrown { get; } 
    public bool IsValid { get; } 
    public string FriendlySummary { get; } 
    // whatever else properties you think are needed 
} 

public IResultState<List<Balance>> GetBalanceFinale(Periode periode) 
{ 
    ResultState<List<Balance>> result = new ResultState<List<Balance>>(); 
    try 
    { 
    if (periode == null 
     || periode.DateStart >= DateTime.Now 
     || isBalanceFinished(periode.PeriodeID)) 
    { 
     result.IsValid = false; 
     result.FriendlySummary = "Periode is in an invalid state."; 
    } 

    //My other code... 

    result.ResultValue = new List<Balance>(); 
    result.ResultValue.Add(...); 

    } 
    catch(Exception ex) 
    { 
    result.IsValid = false; 
    result.Exception = ex; 
    // Ambigious is bad.. so for bad example.. 
    result.FriendlySummary = "An unknown exception happened.";  
    } 
} 
2

你需要重新因子您的代碼第一。在致電GetBalanceFinale之前,您可以驗證它並在驗證失敗時顯示正確的消息。如果驗證通過,您可以撥打GetBalanceFinale方法。

有時您可能無法在調用方法之前進行所有驗證。在這種情況下,你可以用適當的信息拋出異常或使用參數。

2

以前替代我的方法是Notification模式。

這是一種從您的域圖層獲取信息並進入演示文稿的方式。例如,創建如下所示:

public class Notification 
{ 
    public List<Message> Messages; 
    public bool HasMessages; 
    // etc 
} 

並將其實例用作您的域的屬性。

然後你可以做這樣的事情:

myDomain.GetBalanceFinale(periode); 
if(myDomain.Notification.HasMessages) 
    // get the messages and do something with them