首页 > 代码库 > Util应用程序框架公共操作类(三):数据类型转换公共操作类(扩展篇)

Util应用程序框架公共操作类(三):数据类型转换公共操作类(扩展篇)

  上一篇以TDD方式介绍了数据类型转换公共操作类的开发,并提供了单元测试和实现代码,本文将演示通过扩展方法来增强公共操作类,以便调用时更加简化。

  下面以字符串转换为List<Guid>为例进行讨论。

string input = "83B0233C-A24F-49FD-8083-1337209EBC9A,EAB523C6-2FE7-47BE-89D5-C6D440C3033A";var result = Util.Conv.ToGuidList( input );

  观察上面的代码,它确实已经被封装起来了,通过一个明确的API进行调用。不过它是最简化形式吗?

  在.Net 4.0提供了一个扩展方法的语法,这是一个非常强大的功能,它通过静态方法的方式向目标类型添加一个模拟的实例方法。

  上面例子就被简化成如下形式。

string input = "83B0233C-A24F-49FD-8083-1337209EBC9A,EAB523C6-2FE7-47BE-89D5-C6D440C3033A";var result = input.ToGuidList();

  这样在调用的时候就会更爽,从而帮助我们在项目开发过程中进一步减轻负担。

  下面在Util.Tests单元测试项目中添加一个Extensions文件夹,并在Extensions文件夹中添加ConvertExtensionTest.cs的文件,类名为ConvertExtensionTest,用来测试类型转换扩展。

  ConvertExtensionTest代码如下。

  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         /// 转换为Guid101         /// </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         /// 转换为可空Guid112         /// </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 = http://www.mamicode.com/null;149             Assert.AreEqual( string.Empty, value.ToStr() );150             value = http://www.mamicode.com/1;151             Assert.AreEqual( "1", value.ToStr() );152         }153     }154 }

  在Util类库项目中,添加Extensions.Convert.cs文件,类名为Extensions,它是一个静态类,这是扩展方法的强制要求,并且它还是一个部分类,这是因为以后需要进行扩展时,就可以在Extensions类中继续扩展其它功能。

  Extensions.Convert.cs中的代码如下。

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 =http://www.mamicode.com/= 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

Util应用程序框架公共操作类(三):数据类型转换公共操作类(扩展篇)