[英]What is best practice for returning value or error message from method in c#?
我試圖找到最干凈的解決方案,用於從 c# 中的函數/方法返回值或錯誤消息。
現在我已經嘗試過:
public float ValidateValue (float value)
{
if (value == VALID_VALUE)
{
return value;
}
else
{
throw new ArgumentException("Invalid value", "value");
}
}
這個解決方案似乎已經足夠好了,但在我發現的清潔代碼便宜表中:
對控制流使用異常——不要這樣做
對控制流使用異常:性能不佳,難以理解並導致對真實異常情況的處理非常困難。
在無效輸入的情況下你會怎么做?
如果您在 UI 級別編寫從用戶那里獲取輸入的代碼,那么執行以下操作最有意義:
private bool IsValid(float value)
{
return value == VALID_VALUE; // replace with real check.
}
然后在調用代碼中,您將擁有:
public void ReactToInput()
{
float value = HoweverYouGetTheFloatFromTheUser();
if(!IsValid)
{
//Code to display error message.
}
else
{
//Code to do something useful.
//
//Code to display result.
}
}
因為你在這個級別的工作是“接受用戶給我的東西,盡我所能返回他們想要的東西”,在這個級別,最好讓用戶有可能在前面和中間做一些不正確的事情。
如果您正在為其他代碼編寫代碼以供使用,那么執行以下操作最有意義:
private void CheckValid(float valid)
{
if(value != VALID_VALUE) // replace with real check.
throw new ArgumentException();
}
然后在調用代碼中,您將擁有:
public float DoWork(float value)
{
CheckValid(value)
//Code to do something useful.
//
//Code to return result.
}
在這里你的工作是做方法的任務就是干凈和(或返回meaninful結果void
如果沒有一個)。 如果你不能做那份工作,因為你得到的輸入是無稽之談(或出於任何其他原因),那么你需要盡快停下來處理那個問題。 您可以通過每次返回錯誤/成功代碼並每次調用代碼檢查它來做到這一點,但是雖然這種方法確實有一些優點,但例外情況讓我們:
對於 1 的示例,比較:
private bool WithExceptions()
{
return A() > B() && C() > D();
}
private bool WithExplicitChecks(out bool result)
{
result = false;
int a;
int b;
if(!A(out a))
return false;
if(!B(out b))
return false;
if(a <= b)
return true;
int c;
int d;
if(!C(out c))
return false;
if(!D(out d))
return false;
result = c > d;
return true;
}
對於 2 的示例,請考慮:
private void A()
{
if(_someField == null)
throw new InvalidOperationException("field not ready");
_someField.DoSomething();
}
private void B()
{
A();
}
private void C()
{
B();
}
private string D()
{
try
{
C();
}
catch(InvalidOperationException)
{
Console.Error.WriteLine("Was not ready");
}
}
顯然,在真實情況下, B()
和C()
做更多的事情,但是我們在這里可以看到,只有A()
需要擔心引發異常,只有D()
需要處理異常, B()
和C()
可以兩者都只專注於主要問題。*
這兩種方法可以混合使用。 考慮:
private static string CheckValid(string path)
{
if(path.Length == 0)
return "You cannot enter an empty file path";
switch(path[path.Length - 1])
{
case '\\':
case '/':
return "You cannot enter a directory path";
}
return null;
}
public static void Main(string[] args)
{
Console.WriteLine("Enter a file path");
var path = Console.ReadLine().Trim();
var validationError = CheckValid(path);
if(validationError != null)
Console.Error.WriteLine(validationError);
else
{
try
{
using(var reader = new StreamReader(path))
Console.WriteLine(reader.ReadToEnd());
}
catch(FileNotFoundException)
{
Console.Error.WriteLine("File not found");
}
catch(UnauthorizedAccessException)
{
Console.Error.WriteLine("Access denied");
}
catch(IOException ioe)
{
Console.Error.WriteLine(string.Format("I/O Exception: {0}", ioe.Message));
}
}
Console.Read();
}
這個簡單的程序從用戶那里獲取文件路徑,打開相關文件並將內容作為文本輸出。 它采用兩種方法進行錯誤處理。
因為我們可以很容易地檢查空的無效輸入,或者以/
或\\
結尾的無效輸入,這是通過簡單的控制流完成的,我們會顯示一條錯誤消息而不是做一些事情。
我們只能通過嘗試打開文件並失敗來了解其他問題,因此在這些情況下我們會處理異常。 我將針對兩種類型問題的顯式檢查與針對一般問題的顯式檢查結合起來,並相應地采取行動。
這里有第三種異常處理; 如果發生了我根本不希望發生的異常,程序就會失敗,並為調試目的轉儲異常消息。 在沒有捕獲所有異常的任何地方都是這種情況,但非常有用; 因為我沒有全面的catch
或catch(Exception)
我不會混淆我期望處理的異常(去我處理它們!)發生(噓我!現在我必須修復它)。
這是一個簡單的程序,它從用戶那里獲取文件路徑,並輸出文件的內容。 請注意,它結合了兩種方法:
*盡管總是考慮到如果異常通過它,方法中啟動的某些東西可能不會完成。
如果您想驗證某些輸入值,我希望返回一個bool
值,指示“有效”或“無效”,或者沒有返回值並在該值無效時拋出異常。
所以我建議使用這個:
public bool ValidateValue(float value)
{
return value == VALID_VALUE;
}
或這個:
public void ValidateValue(float value)
{
if (value != VALID_VALUE)
{
throw new ArgumentException("Invalid value", "value");
}
}
所以拋出異常不是問題,尤其是有多種拒絕原因,而你又想區分各種原因的時候。 否則,只需使用bool
,例如int.TryParse
。
元組可能有助於解決該問題:
public Tuple<float,string> ValidateValue (float value)
if (value == VALID_VALUE)
{
return new Tuple<bool, string>(value,string.Empty);
}
else
{
return new Tuple<bool, string>(false,"Invalid value");
}
調用函數時,首先檢查錯誤字符串是否為空:
var validation = ValidateValue(myFloatValue);
if (validation.Item2 != string.Empty)
{
// report error
}
else
{
// No error core here validation.Item1 is your result
}
一種想法可能是擁有一些通用模型。 您可能有一些模型,大致如下:
public class MyReturnModel
{
public bool Success { get; set; }
public string ErrorOrSuccessMessage { get; set; }
public dynamic AnyModelToReturn { get; set; }
}
現在讓我們將其應用於您提供的案例:
public MyReturnModel ValidateValue(float value)
{
//function logic here
bool result = value == VALID_VALUE;
string msg = result ? "valud is valid" : "value is invalid";
return new MyReturnModel { Success = result, ErrorOrSuccessMessage = msg }
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.