使用自定義隱式轉換快速創建失敗Result
- 2022 年 8 月 24 日
- 筆記
系統要求方法都返回 Result 結果,通常我們會如此定義一個 Result
1 public class Result<T> 2 { 3 public virtual int Code { get; set; } 4 5 public virtual T Data { get; set; } 6 7 public virtual string Message { get; set; } 8 } 9 10 public class Result : Result<object> 11 { 12 // 快速創建成功結果 13 public static Result<T> Success<T>(T data) 14 { 15 return new Result<T>() { Data = data }; 16 } 17 18 // 快速創建失敗結果 19 public static Result<T> Fail<T>(int code, string message) 20 { 21 return new Result<T>() { Code = code, Message = message }; 22 } 23 }
得益於C#強大的類型推斷,我們可以非常簡單的返回成功或失敗結果
1 public Result<User> GetUser(int userId) 2 { 3 User user = null; // Read from database 4 if (user == null) 5 { 6 return Result.Fail<User>(400, "用戶不存在"); // 需要手動指明 User,有點煩 7 } 8 else 9 { 10 return Result.Success(user); 11 } 12 }
成功的時候,Success() 方法可以自動推斷出Data為 User 類;
但是失敗的時候,必須手動的指明Data為 User 類,雖然僅僅多敲了幾個字母,但我還是想簡化,因為失敗時,Data根本不需要賦值,也不在乎Data 的類型。
C# 可以使用 Implicit 自定義隱式轉換,可以將 Result 自動隱式轉換轉換為 Result<T>,考慮到我們只需要在失敗的時候才轉換,所以我定義了一個 FailResult
1 public class FailResult : Result 2 { 3 } 4 5 public class Result : Result<object> 6 { 7 // 新增加的方法 8 public static FailResult Fail(int code, string message) 9 { 10 return new FailResult() { Code = code, Message = message }; 11 } 12 }
這樣的話,不論時成功還是失敗,我們都不需要指定Data 的類型了
1 public Result<User> GetUser(int userId) 2 { 3 User user = null; // Read from database 4 if (user == null) 5 { 6 return Result.Fail(400, "用戶不存在"); // 不用指明 <User> 了 7 } 8 else 9 { 10 return Result.Success(user); 11 } 12 }
心細的朋友會發現,這種 Result.Fail 其實是先 new 一個 FailResult,然後編譯器再 new 一個 Result<T>, 事實上多創建了一個無用的實例,但我覺得對於CLR而言這種開銷可以忽略不記。
下面是完整的程式碼:


1 using System; 2 3 namespace ConsoleApp1 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 Console.WriteLine("Hello World!"); 10 } 11 12 public Result<User> GetUser(int userId) 13 { 14 User user = null; // Read from database 15 if (user == null) 16 { 17 return Result.Fail(400, "用戶不存在"); // 不用指明 <User> 了 18 //return Result.Fail<User>(400, "用戶不存在"); 19 } 20 else 21 { 22 return Result.Success(user); 23 } 24 } 25 } 26 27 public class Result<T> 28 { 29 public virtual int Code { get; set; } 30 31 public virtual T Data { get; set; } 32 33 public virtual string Message { get; set; } 34 35 36 public static implicit operator Result<T>(FailResult failResult) 37 { 38 return new Result<T>() { Code = failResult.Code, Message = failResult.Message }; 39 } 40 } 41 42 public class Result : Result<object> 43 { 44 public static Result<T> Success<T>(T data) 45 { 46 return new Result<T>() { Data = data }; 47 } 48 49 public static Result<T> Fail<T>(int code, string message) 50 { 51 return new Result<T>() { Code = code, Message = message }; 52 } 53 54 public static FailResult Fail(int code, string message) 55 { 56 return new FailResult() { Code = code, Message = message }; 57 } 58 } 59 60 public class FailResult : Result 61 { 62 } 63 64 public class User 65 { 66 } 67 }
View Code