上一篇以TDD方式介紹了數據類型轉換公共操做類的開發,並提供了單元測試和實現代碼,本文將演示經過擴展方法來加強公共操做類,以便調用時更加簡化。程序員
下面以字符串轉換爲List<Guid>爲例進行討論。框架
string input = "83B0233C-A24F-49FD-8083-1337209EBC9A,EAB523C6-2FE7-47BE-89D5-C6D440C3033A"; var result = Util.Conv.ToGuidList( input );
觀察上面的代碼,它確實已經被封裝起來了,經過一個明確的API進行調用。不過它是最簡化形式嗎?單元測試
在.Net 3.0提供了一個擴展方法的語法,這是一個很是強大的功能,它經過靜態方法的方式向目標類型添加一個模擬的實例方法。測試
上面例子就被簡化成以下形式。ui
string input = "83B0233C-A24F-49FD-8083-1337209EBC9A,EAB523C6-2FE7-47BE-89D5-C6D440C3033A"; var result = input.ToGuidList();
這樣在調用的時候就會更爽,從而幫助咱們在項目開發過程當中進一步減輕負擔。this
下面在Util.Tests單元測試項目中添加一個Extensions文件夾,並在Extensions文件夾中添加ConvertExtensionTest.cs的文件,類名爲ConvertExtensionTest,用來測試類型轉換擴展。spa
ConvertExtensionTest代碼以下。code
1 using System; 2 using System.Collections.Generic; 3 using Microsoft.VisualStudio.TestTools.UnitTesting; 4
5 namespace Util.Tests.Extensions { 6 /// <summary>
7 /// 類型轉換擴展測試 8 /// </summary>
9 [TestClass] 10 public class ConvertExtensionTest { 11 /// <summary>
12 /// 轉換爲整數 13 /// </summary>
14 [TestMethod] 15 public void TestToInt() { 16 string obj1 = ""; 17 string obj2 = "1"; 18 Assert.AreEqual( 0, obj1.ToInt() ); 19 Assert.AreEqual( 1, obj2.ToInt() ); 20 } 21
22 /// <summary>
23 /// 轉換爲可空整數 24 /// </summary>
25 [TestMethod] 26 public void TestToIntOrNull() { 27 string obj1 = ""; 28 string obj2 = "1"; 29 Assert.IsNull( obj1.ToIntOrNull() ); 30 Assert.AreEqual( 1, obj2.ToIntOrNull() ); 31 } 32
33 /// <summary>
34 /// 轉換爲雙精度浮點數 35 /// </summary>
36 [TestMethod] 37 public void TestToDouble() { 38 string obj1 = ""; 39 string obj2 = "1.2"; 40 Assert.AreEqual( 0, obj1.ToDouble() ); 41 Assert.AreEqual( 1.2, obj2.ToDouble() ); 42 } 43
44 /// <summary>
45 /// 轉換爲可空雙精度浮點數 46 /// </summary>
47 [TestMethod] 48 public void TestToDoubleOrNull() { 49 string obj1 = ""; 50 string obj2 = "1.2"; 51 Assert.IsNull( obj1.ToDoubleOrNull() ); 52 Assert.AreEqual( 1.2, obj2.ToDoubleOrNull() ); 53 } 54
55 /// <summary>
56 /// 轉換爲高精度浮點數 57 /// </summary>
58 [TestMethod] 59 public void TestToDecimal() { 60 string obj1 = ""; 61 string obj2 = "1.2"; 62 Assert.AreEqual( 0, obj1.ToDecimal() ); 63 Assert.AreEqual( 1.2M, obj2.ToDecimal() ); 64 } 65
66 /// <summary>
67 /// 轉換爲可空高精度浮點數 68 /// </summary>
69 [TestMethod] 70 public void TestToDecimalOrNull() { 71 string obj1 = ""; 72 string obj2 = "1.2"; 73 Assert.IsNull( obj1.ToDecimalOrNull() ); 74 Assert.AreEqual( 1.2M, obj2.ToDecimalOrNull() ); 75 } 76
77 /// <summary>
78 /// 轉換爲日期 79 /// </summary>
80 [TestMethod] 81 public void TestToDate() { 82 string obj1 = ""; 83 string obj2 = "2000-1-1"; 84 Assert.AreEqual( DateTime.MinValue, obj1.ToDate() ); 85 Assert.AreEqual( new DateTime( 2000, 1, 1 ), obj2.ToDate() ); 86 } 87
88 /// <summary>
89 /// 轉換爲可空日期 90 /// </summary>
91 [TestMethod] 92 public void TestToDateOrNull() { 93 string obj1 = ""; 94 string obj2 = "2000-1-1"; 95 Assert.IsNull( obj1.ToDateOrNull() ); 96 Assert.AreEqual( new DateTime( 2000, 1, 1 ), obj2.ToDateOrNull() ); 97 } 98
99 /// <summary>
100 /// 轉換爲Guid 101 /// </summary>
102 [TestMethod] 103 public void TestToGuid() { 104 string obj1 = ""; 105 string obj2 = "B9EB56E9-B720-40B4-9425-00483D311DDC"; 106 Assert.AreEqual( Guid.Empty, obj1.ToGuid() ); 107 Assert.AreEqual( new Guid( obj2 ), obj2.ToGuid() ); 108 } 109
110 /// <summary>
111 /// 轉換爲可空Guid 112 /// </summary>
113 [TestMethod] 114 public void TestToGuidOrNull() { 115 string obj1 = ""; 116 string obj2 = "B9EB56E9-B720-40B4-9425-00483D311DDC"; 117 Assert.IsNull( obj1.ToGuidOrNull() ); 118 Assert.AreEqual( new Guid( obj2 ), obj2.ToGuidOrNull() ); 119 } 120
121 /// <summary>
122 /// 轉換爲Guid集合,值爲字符串 123 /// </summary>
124 [TestMethod] 125 public void TestToGuidList_String() { 126 const string guid = "83B0233C-A24F-49FD-8083-1337209EBC9A,,EAB523C6-2FE7-47BE-89D5-C6D440C3033A,"; 127 Assert.AreEqual( 2, guid.ToGuidList().Count ); 128 Assert.AreEqual( new Guid( "83B0233C-A24F-49FD-8083-1337209EBC9A" ), guid.ToGuidList()[0] ); 129 Assert.AreEqual( new Guid( "EAB523C6-2FE7-47BE-89D5-C6D440C3033A" ), guid.ToGuidList()[1] ); 130 } 131
132 /// <summary>
133 /// 轉換爲Guid集合,值爲字符串集合 134 /// </summary>
135 [TestMethod] 136 public void TestToGuidList_StringList() { 137 var list = new List<string> {"83B0233C-A24F-49FD-8083-1337209EBC9A", "EAB523C6-2FE7-47BE-89D5-C6D440C3033A"}; 138 Assert.AreEqual( 2, list.ToGuidList().Count ); 139 Assert.AreEqual( new Guid( "83B0233C-A24F-49FD-8083-1337209EBC9A" ), list.ToGuidList()[0] ); 140 Assert.AreEqual( new Guid( "EAB523C6-2FE7-47BE-89D5-C6D440C3033A" ), list.ToGuidList()[1] ); 141 } 142
143 /// <summary>
144 /// 轉換爲字符串 145 /// </summary>
146 [TestMethod] 147 public void TestToStr() { 148 object value = null; 149 Assert.AreEqual( string.Empty, value.ToStr() ); 150 value = 1; 151 Assert.AreEqual( "1", value.ToStr() ); 152 } 153 } 154 }
在Util類庫項目中,添加Extensions.Convert.cs文件,類名爲Extensions,它是一個靜態類,這是擴展方法的強制要求,而且它仍是一個部分類,這是由於之後須要進行擴展時,就能夠在Extensions類中繼續擴展其它功能。對象
Extensions.Convert.cs中的代碼以下。blog
using System; using System.Collections.Generic; using System.Linq; namespace Util { /// <summary>
/// 類型轉換擴展 /// </summary>
public static partial class Extensions { /// <summary>
/// 轉換爲int /// </summary>
/// <param name="data">數據</param>
public static int ToInt( this string data ) { return Conv.ToInt( data ); } /// <summary>
/// 轉換爲可空int /// </summary>
/// <param name="data">數據</param>
public static int? ToIntOrNull( this string data ) { return Conv.ToIntOrNull( data ); } /// <summary>
/// 轉換爲double /// </summary>
/// <param name="data">數據</param>
public static double ToDouble( this string data ) { return Conv.ToDouble( data ); } /// <summary>
/// 轉換爲可空double /// </summary>
/// <param name="data">數據</param>
public static double? ToDoubleOrNull( this string data ) { return Conv.ToDoubleOrNull( data ); } /// <summary>
/// 轉換爲decimal /// </summary>
/// <param name="data">數據</param>
public static decimal ToDecimal( this string data ) { return Conv.ToDecimal( data ); } /// <summary>
/// 轉換爲可空decimal /// </summary>
/// <param name="data">數據</param>
public static decimal? ToDecimalOrNull( this string data ) { return Conv.ToDecimalOrNull( data ); } /// <summary>
/// 轉換爲日期 /// </summary>
/// <param name="data">數據</param>
public static DateTime ToDate( this string data ) { return Conv.ToDate( data ); } /// <summary>
/// 轉換爲可空日期 /// </summary>
/// <param name="data">數據</param>
public static DateTime? ToDateOrNull( this string data ) { return Conv.ToDateOrNull( data ); } /// <summary>
/// 轉換爲Guid /// </summary>
/// <param name="data">數據</param>
public static Guid ToGuid( this string data ) { return Conv.ToGuid( data ); } /// <summary>
/// 轉換爲可空Guid /// </summary>
/// <param name="data">數據</param>
public static Guid? ToGuidOrNull( this string data ) { return Conv.ToGuidOrNull( data ); } /// <summary>
/// 轉換爲Guid集合 /// </summary>
/// <param name="data">數據,範例: "83B0233C-A24F-49FD-8083-1337209EBC9A,EAB523C6-2FE7-47BE-89D5-C6D440C3033A"</param>
public static List<Guid> ToGuidList( this string data ) { return Conv.ToGuidList( data ); } /// <summary>
/// 轉換爲Guid集合 /// </summary>
/// <param name="data">字符串集合</param>
public static List<Guid> ToGuidList( this IList<string> data ) { if ( data == null ) return new List<Guid>(); return data.Select( t => t.ToGuid() ).ToList(); } /// <summary>
/// 獲取字符串 /// </summary>
/// <param name="data">對象</param>
public static string ToStr( this object data ) { return Conv.ToString( data ); } } }
爲了不代碼冗餘,在數據類型擴展類中,會將調用委託給conv進行處理,而不是在擴展類中從新實現一次。
擴展方法的一個弊端是可能污染原生的.Net環境,從而致使混亂,特別是在擴展object對象時要十分當心,由於會添加到每一個對象中。從我提供的示例代碼能夠看到,我主要是在string對象上擴展,由於這樣範圍會小得多。
對因而否會濫用擴展方法,個人建議是若是你的應用程序框架使用範圍很小,那麼沒必要理會其它人的見解,使勁擴展直至你本身都以爲負擔重重,而後再進行減肥。可是,當框架使用範圍比較大,應該儘可能不污染系統原生類,由於不少程序員在代碼提示中找到這些API後,可能在不瞭解的狀況下胡亂調用致使BUG,且因爲使用範圍大,框架建立人不能及時糾正其它人的問題。
.Net應用程序框架交流QQ羣: 386092459,歡迎有興趣的朋友加入討論。
謝謝你們的持續關注,個人博客地址:http://www.cnblogs.com/xiadao521/
下載地址:http://files.cnblogs.com/xiadao521/Util.2014.11.13.1.rar