程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> c#擴展方法奇思妙用高級篇五:ToString(string format) 擴展(3)

c#擴展方法奇思妙用高級篇五:ToString(string format) 擴展(3)

編輯:關於C語言

對於簡單的值類型屬性沒問題了,但對於復雜一些類型如,如People的屬性Son(Son就是兒子,我一開始寫成了Sun),他也是一個People類型,他也有屬性的,而且他也可能有Son...

先看下調用代碼吧:

1 People p4 = new People { Id = 1, Name = "鶴沖天", Brithday = new DateTime(1990, 9, 9) };
2 p4.Son = new People { Id = 2, Name = "鶴小天", Brithday = new DateTime(2015, 9, 9) };
3 p4.Son.Son = new People { Id = 3, Name = "鶴微天", Brithday = new DateTime(2040, 9, 9) };
4 string s4 = p4.ToString4("[Name] 的孫子 [Son.Son.Name] 的生日是:[Son.Son.Brithday: yyyy年MM月dd日]。");

“鶴沖天”也就是我了,有個兒子叫“鶴小天”,“鶴小天”有個兒子,也就是我的孫子“鶴微天”。哈哈,祖孫三代名字都不錯吧(過會先把小天、微天這兩個名字注冊了)!主要看第4行,format是怎麼寫的。下面是版本四實現代碼,由版本三改進而來:

1 public static string ToString4(this object obj, string format)
2 {
3  MatchEvaluator evaluator = match =>
4   {
5    string[] propertyNames = match.Groups["Name"].Value.Split('.');
6    string propertyFormat = match.Groups["Format"].Value;
7
8    object propertyValue = obj;
9    try
10    {
11     foreach (string propertyName in propertyNames)
12      propertyValue = propertyValue.GetPropertyValue(propertyName);
13    }
14    catch
15    {
16     return match.Value;
17    }
18
19    if (string.IsNullOrEmpty(format) == false)
20     return string.Format("{0:" + propertyFormat + "}", propertyValue);
21    else return propertyValue.ToString();
22 };
23  string pattern = @"\[(?<Name>[^\[\]:]+)(\s*[:]\s*(?<Format>[^\[\]:]+))?\]";
24  return Regex.Replace(format, pattern, evaluator, RegexOptions.Compiled);
25 }

為了反射獲取屬性方法,用到了GetPropertyValue擴展如下(版本三的實現用上這個擴展會更簡潔)(考慮性能請在此方法加緩存):

1 public static object GetPropertyValue(this object obj, string propertyName)
2 {
3  Type type = obj.GetType();
4  PropertyInfo info = type.GetProperty(propertyName);
5  return info.GetValue(obj, null);
6 }

先執行,再分析:

 

執行正確! 版本四,8~17行用來層層獲取屬性。也不太復雜,不多作解釋了。說明一下,版本四是不完善的,沒有做太多處理。

我們最後再來看一下更復雜的應用,Peoplee有FrIEnds屬性,這是一個集合屬性,我們想獲取朋友的個數,並列出朋友的名字,如下:

1 People p5 = new People { Id = 1, Name = "鶴沖天"};
2 p5.AddFrIEnd(new People { Id = 11, Name = "南霸天" });
3 p5.AddFrIEnd(new People { Id = 12, Name = "日中天" });
4 string s5 = p5.ToString5("[Name] 目前有 [Friends: .Count] 個朋友:[FrIEnds: .Name]。");

注意,行4中的Count及Name前都加了個小點,表示是將集合進行操作,這個小點是我看著方便自己定義的。再來看實現代碼,到版本五了:

1 public static string ToString5(this object obj, string format)
2  {
3   MatchEvaluator evaluator = match =>
4   {
5    string[] propertyNames = match.Groups["Name"].Value.Split('.');
6    string propertyFormat = match.Groups["Format"].Value;
7
8    object propertyValue = obj;
9 
10   try
11    {
12     foreach (string propertyName in propertyNames)
13      propertyValue = propertyValue.GetPropertyValue(propertyName);
14    }
15    catch
16    {
17     return match.Value;
18    }
19
20    if (string.IsNullOrEmpty(propertyFormat) == false)
21    {
22     if (propertyFormat.StartsWith("."))
23     {
24      string subPropertyName = propertyFormat.Substring(1);
25      IEnumerable<object> obJS = ((IEnumerable)propertyValue).Cast<object>();
26      if (subPropertyName == "Count")
27       return obJS.Count().ToString();
28      else
29       {
30        string[] subPropertIEs = obJS.Select(
31        o => o.GetPropertyValue(subPropertyName).ToString()).ToArray();
32        return string.Join(", ", subPropertIEs);
33       }
34     }
35     else
36      return string.Format("{0:" + propertyFormat + "}", propertyValue);
37    }
38    else return propertyValue.ToString();
39  };
40  string pattern = @"\[(?<Name>[^\[\]:]+)(\s*[:]\s*(?<Format>[^\[\]:]+))?\]";
41  return Regex.Replace(format, pattern, evaluator, RegexOptions.Compiled);
42 }

執行結果:

比較不可思議吧,下面簡單分析一下。行22~行33是對集合進行操作的相關處理,這裡只是簡單實現了Count,當然也可以實現Min、Max、Sum、Average等等。“.Name”這個表示方法不太好,這裡主要是為了展示,大家能明白了就好。

就寫到這裡吧,版本六、版本七...後面還很多,當然一個比一個離奇,不再寫了。給出五個版本,版本一存在問題,主要看後三個版本,給出多個版本是為滿足不同朋友的需要,一般來說版本三足夠,對於要求比較高,追求新技術的朋友,我推薦版本四、五。要求更高的,就是沒給出的六、七...了。

ToString(string format)擴展帶來便利性的同時,也會帶來相應的性能損失,兩者很難兼得。

最後重申下,本系列文章,側重想法,所給的代碼僅供演示、參考,沒有考慮性能、異常處理等,如需實際使用,請自行完善。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved