C#_Extension Method技巧
C#預設有些函數功能在使用上可能會覺得有些微不足
因此偶而會想自行做擴充
擴充方法可讓您在現有類型中「加入」方法,而不需要建立新的衍生類型、重新編譯,或是修改原始類型。
別於自行定義的function ,其可讓我們在現有的內建物件中做擴展方法。
可以在專案新增一個Extention目錄並額外新增一個class取名為CustomExtention
用public static修飾 裡面自行建立的各種method也必須是public static
Case.1 兩個Dictionary Merge的功能擴充
我想要實作Dictionary A 去merge Dictionary B返回一個合併的Dictionary的功能
由於.net Dictionary本身型別內建沒提供該功能
CustomExtension.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ExtensionMethodApp.Extension { public static class CustomExtension { public static Dictionary<Key, Value> MergeDic<Key, Value>(this Dictionary<Key, Value> left, Dictionary<Key, Value> right) { if (left == null) { throw new ArgumentNullException("Can't merge into a null dictionary"); } else if (right == null) { return left; } foreach (var kvp in right) { if (!left.ContainsKey(kvp.Key)) { left.Add(kvp.Key, kvp.Value); } } return left; } } } |
外部在使用時候引用該命名空間
using ExtensionMethodApp.Extension;
Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | using ExtensionMethodApp.Extension; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ExtensionMethodApp { class Program { static void Main(string[] args) { Dictionary<string, string> dicA = new Dictionary<string, string>(); dicA.Add("A", "Almond"); dicA.Add("B", "Berry"); Dictionary<string, string> dicB = new Dictionary<string, string>(); dicA.Add("C", "Cherry"); dicA.Add("D", "Damson"); Dictionary<string,string> dicRes = dicA.MergeDic(dicB); Console.ReadKey(); } } } |
Case.2 判斷字串內文是否為Json格式的String 擴充
這裡我們補安裝完Newtonsoft.Json並引入相應namespace
於CustomExtension新增程式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ExtensionMethodApp.Extension { public static class CustomExtension { public static Dictionary<Key, Value> MergeDic<Key, Value>(this Dictionary<Key, Value> left, Dictionary<Key, Value> right) { if (left == null) { throw new ArgumentNullException("Can't merge into a null dictionary"); } else if (right == null) { return left; } foreach (var kvp in right) { if (!left.ContainsKey(kvp.Key)) { left.Add(kvp.Key, kvp.Value); } } return left; } /// <summary> /// Determine input string is json format /// </summary> /// <param name="value"></param> /// <returns></returns> public static bool IsJsonFormat(this string value) { if (string.IsNullOrWhiteSpace(value)) return false; if ((value.StartsWith("{") && value.EndsWith("}")) || (value.StartsWith("[") && value.EndsWith("]"))) { try { var obj = JToken.Parse(value); return true; } catch (JsonReaderException) { return false; } } return false; } } } |
在外部調用測試是否為json格式時候就可以這樣子來判斷
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | using ExtensionMethodApp.Extension; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ExtensionMethodApp { class Program { static void Main(string[] args) { string str_json = ""; if (str_json.IsJsonFormat()) { } else { str_json = "{'name':'John', 'age':30, 'car':null}"; if (str_json.IsJsonFormat()) { } } Console.ReadKey(); } } } |
Case.3 Enum想要取實際的字串值定義而非原本的數字
實務上enum會因為相關的資料而去特別定義再一起的資料結構
然而直接透過enum預設數值編號不太容易識別
也會希望直接取得enum對應的字串值
C# Enum中我們可以自定義客製的attribute標記在enum項目上
比方像DescriptionAttribute
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | using ExtensionMethodApp.Extension; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ExtensionMethodApp { class Program { public enum ContentTypeOption { [Description("application/x-www-form-urlencoded")] form_urlencoded, [Description("application/json")] json_format, [Description("application/xml")] xml_format, [Description("application/exchange+xml")] ex_xml_format, [Description("application/pdf")] pdf_format, [Description("application/msword")] msword_format, [Description("multipart/form-data")] multipart_form_data, [Description("text/plain")] text_plain, [Description("text/html")] text_html, [Description("text/xml")] text_xml, [Description("image/gif")] image_gif, [Description("image/png")] image_png, [Description("image/jpeg")] image_jpeg, } static void Main(string[] args) { ContentTypeOption contentTypeOption = ContentTypeOption.image_jpeg; Console.ReadKey(); } } } |
但功能仍不太足夠
因為我們想要去取得該字串描述的實質定義
此時我們可先去自己建立客製的Attribute
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ExtensionMethodApp.Extension { public class StringValueAttribute : Attribute { public string StringValue { get; protected set; } public StringValueAttribute(string value) { this.StringValue = value; } } } |
之後再添增於enum項目中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | using ExtensionMethodApp.Extension; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ExtensionMethodApp { class Program { public enum ContentTypeOption { [StringValueAttribute("application/x-www-form-urlencoded")] form_urlencoded, [StringValueAttribute("application/json")] json_format, [StringValueAttribute("application/xml")] xml_format, [StringValueAttribute("application/exchange+xml")] ex_xml_format, [StringValueAttribute("application/pdf")] pdf_format, [StringValueAttribute("application/msword")] msword_format, [StringValueAttribute("multipart/form-data")] multipart_form_data, [StringValueAttribute("text/plain")] text_plain, [StringValueAttribute("text/html")] text_html, [StringValueAttribute("text/xml")] text_xml, [StringValueAttribute("image/gif")] image_gif, [StringValueAttribute("image/png")] image_png, [StringValueAttribute("image/jpeg")] image_jpeg, } static void Main(string[] args) { ContentTypeOption contentTypeOption = ContentTypeOption.image_jpeg; Console.ReadKey(); } } } |
接著進行Extension Method的擴充設計
由於有運用到Reflection的api因此
using System.Reflection;記得引入
在此擴充GetStringValue
用於直接取得enum item的string attribute
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace ExtensionMethodApp.Extension { public static class CustomExtension { /// <summary> /// Will get the string value for a given enums value, this will /// only work if you assign the StringValue attribute to /// the items in your enum. /// </summary> /// <param name="value"></param> /// <returns></returns> public static string GetStringValue(this Enum value) { Type type = value.GetType(); FieldInfo fieldInfo = type.GetField(value.ToString()); StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[]; return attribs.Length > 0 ? attribs[0].StringValue : null; } public static Dictionary<Key, Value> MergeDic<Key, Value>(this Dictionary<Key, Value> left, Dictionary<Key, Value> right) { if (left == null) { throw new ArgumentNullException("Can't merge into a null dictionary"); } else if (right == null) { return left; } foreach (var kvp in right) { if (!left.ContainsKey(kvp.Key)) { left.Add(kvp.Key, kvp.Value); } } return left; } /// <summary> /// Determine input string is json format /// </summary> /// <param name="value"></param> /// <returns></returns> public static bool IsJsonFormat(this string value) { if (string.IsNullOrWhiteSpace(value)) return false; if ((value.StartsWith("{") && value.EndsWith("}")) || (value.StartsWith("[") && value.EndsWith("]"))) { try { var obj = JToken.Parse(value); return true; } catch (JsonReaderException) { return false; } } return false; } } } |
而在外部調用時候就能成功把string 屬性的定義取出
擴充方法 (C# 程式設計手冊)
https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/classes-and-structs/extension-methods
留言
張貼留言