【設計原則和建議】 方法返回值
基本規則
1.不要忽略返回值;如果不想處理返回值,就選擇沒有返回值的方法(如果有的話)
2.公開給第三方的方法返回值類型在滿足功能的情況下,盡量選擇父類和接口,而不是具體類型 (面向對象的封裝性)
- 這點可能有很大的爭議,我區分為對外的和對內的方法 (對內請看No.3)
- 返回子類,意味要把子類的細節也暴露出去
- 使用接口返回具體類型,就不用暴露細節了
public class ClassP //請忽略嵌套類的設計問題
{
protected internal class User : IUser//我不想暴露User類的細節給外部 注:也可能是private等的訪問性
{
public void ResetMoney() { }
}
public IUser GetUser()
{
return new User();
}
}
public interface IUser
{
}
class Program
{
static void Main(string[] args)
{
ClassP p = new ClassP();
var user = p.GetUser();
}
}
- 下面又是一個返回具體類型的悲劇(一般不建議直接暴露內部集合成員,而是使用Clone等方法返回副本,或者使用 IEnumerable<T>)
class Program
{
static void Main(string[] args)
{
ClassS s = new ClassS();
var list = s.GetList();
s.PrintListCount();
list.Add("string");
s.PrintListCount();//這里輸出1個, ClassS的內部變量被改變了,破壞了封裝性
}
}
public class ClassS
{
private List<string> list = new List<string>();
public List<string> GetList()//bad
{
return list;
}
public IEnumerable<string> GetList2()//good
{
return list;
}
public void PrintListCount()
{
Console.WriteLine(list.Count());
}
}
- 有時候為了保持行為的一致性而選擇返回父類 ( WebRequest HttpWebRequest.Create(string requestUriString);)
3.內部方法(如private)盡可能選擇詳細類型
- 調用方得到更多細節信息,可以做更多的操作
- 除非是設計上使用了工廠模式等設計方式,那只能返回接口或者父類了 (返回類型是父類,實際類型還是子類)
4.建議將返回值存在本地變量以后再使用
- 鏈式表達式是例外情況
5.將接口作為返回值,往往意味著該設計希望解耦合
6.別為了方便或者是懶惰把方法返回值都弄成Object
7.優先使用返回值,而不是ref和out參數
8.參數類型和方法名保持一致
- 如果是鏈式表達式,自然返回值類型和類本身保持一致
IQueryable<ClassX> list = null;//只是為了演示 所以沒有值
var data = list.OrderBy(p => p.Age).Where(p => p.Type == 1).ToList();
返回值和異常
1.為什么選擇異常
- 一般情況下,在內部使用的方法中,使用異常來提示執行錯誤,而不是用返回值
- 所謂內部使用的意思是:該方法不是公開給第三方使用的(例如 組件開發中的public方法, 例如WebService 等)
- 異常不影響正常邏輯代碼的閱讀,也不影響返回值本身的意義(例如 你不需要聲明一個返回值的類 同時返回 狀態碼 異常信息 和真正的數據)
- 相比于返回值,異常的功能信息更為豐富,例如攜帶堆棧跟蹤等
- 相比于返回值,異常的功能更為強大, 例如通過 AppDomain.CurrentDomain.UnhandledException 處理所有未處理的異常
- 使用異常來告知執行失敗和.net類庫本身保持行為一致 例如: System.IO.File.WriteAllText() ;
- 如果使用返回值類通知執行失敗,用戶容易忽略返回值,如下所示
static void Main()
{
GoGoGo();//沒注意到返回值是false
//繼續....
}
static bool GoGoGo()
{
return false;
}
2.為什么選擇返回值
- 外部使用方法中應該使用返回值而不是異常,包括但不僅限于Socket,HTTP,跨語言,跨進程的通信
- asp.net本身 還有WCF 都提供了全局的handler將錯誤轉化為返回的html或者xml (就是我們經常見到的黃色錯誤頁面) 在程序內部使用異常,準備返回的時候使用統一的handler處理為返回值是一個較好的實踐
- 性能問題; 就是為了性能問題.net類庫提供了 Int.TryPrase 方法
返回值類型和值
1. void無返回值
- 不要為了增加返回值而增加返回值,一個東西它如果邏輯上不需要返回值那么就應該設計為void
2.Int 和其他所有的數值類型
- 在數據邏輯上只能是正整數0的時候,使用-1 作為條件不成立的值. 例如String.IndexOf 返回-1代表字符串不存在
- 在數據邏輯上是整數的時候,使用 Int? (Nullable<int>) 并且值為null 作為條件不成立. 例如 int? GetUserId() 用戶不存在的時候返回Null (更推薦的方法是先調用方法判斷用戶是否存在, 然后調用 int GetUserId())
3.String
- 將null作為條件不成立或者無數據的表示
- 傳遞給表現層的返回值考慮返回空字符串 "" (String.Empty) 優先于null (例如在asp.net頁面上直接調用 s.Trim() 等方法會比較方便,不需要判斷null值) 我個人覺得這不算一個嚴謹的設計 但是會方便編碼
4.所有普通的Class (非集合類)
- 將null作為條件不成立或者無數據的表示
5.集合類
- 將集合類型不為null但是數量為0的集合,作為條件不成立或者無數據的表示
6.泛型
- 將Default(T) 作為條件不成立或者無數據的表示
部分內容引用自MSDN,FxCop 和其他第三方文章..
因為本人水平有限,如有遺漏或謬誤,還請各位高手指正
浙公網安備 33010602011771號