Util应用程序框架公共操作类(三):数据类型转换公共操作类(扩展篇)
2014-11-13 14:01
218 查看
上一篇以TDD方式介绍了数据类型转换公共操作类的开发,并提供了单元测试和实现代码,本文将演示通过扩展方法来增强公共操作类,以便调用时更加简化。
下面以字符串转换为List<Guid>为例进行讨论。
观察上面的代码,它确实已经被封装起来了,通过一个明确的API进行调用。不过它是最简化形式吗?
在.Net 3.0提供了一个扩展方法的语法,这是一个非常强大的功能,它通过静态方法的方式向目标类型添加一个模拟的实例方法。
上面例子就被简化成如下形式。
这样在调用的时候就会更爽,从而帮助我们在项目开发过程中进一步减轻负担。
下面在Util.Tests单元测试项目中添加一个Extensions文件夹,并在Extensions文件夹中添加ConvertExtensionTest.cs的文件,类名为ConvertExtensionTest,用来测试类型转换扩展。
ConvertExtensionTest代码如下。
在Util类库项目中,添加Extensions.Convert.cs文件,类名为Extensions,它是一个静态类,这是扩展方法的强制要求,并且它还是一个部分类,这是因为以后需要进行扩展时,就可以在Extensions类中继续扩展其它功能。
Extensions.Convert.cs中的代码如下。
为了避免代码冗余,在数据类型扩展类中,会将调用委托给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
下面以字符串转换为List<Guid>为例进行讨论。
string input = "83B0233C-A24F-49FD-8083-1337209EBC9A,EAB523C6-2FE7-47BE-89D5-C6D440C3033A"; var result = Util.Conv.ToGuidList( input );
观察上面的代码,它确实已经被封装起来了,通过一个明确的API进行调用。不过它是最简化形式吗?
在.Net 3.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代码如下。
using System; using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Util.Tests.Extensions { /// <summary> /// 类型转换扩展测试 /// </summary> [TestClass] public class ConvertExtensionTest { /// <summary> /// 转换为整数 /// </summary> [TestMethod] public void TestToInt() { string obj1 = ""; string obj2 = "1"; Assert.AreEqual( 0, obj1.ToInt() ); Assert.AreEqual( 1, obj2.ToInt() ); } /// <summary> /// 转换为可空整数 /// </summary> [TestMethod] public void TestToIntOrNull() { string obj1 = ""; string obj2 = "1"; Assert.IsNull( obj1.ToIntOrNull() ); Assert.AreEqual( 1, obj2.ToIntOrNull() ); } /// <summary> /// 转换为双精度浮点数 /// </summary> [TestMethod] public void TestToDouble() { string obj1 = ""; string obj2 = "1.2"; Assert.AreEqual( 0, obj1.ToDouble() ); Assert.AreEqual( 1.2, obj2.ToDouble() ); } /// <summary> /// 转换为可空双精度浮点数 /// </summary> [TestMethod] public void TestToDoubleOrNull() { string obj1 = ""; string obj2 = "1.2"; Assert.IsNull( obj1.ToDoubleOrNull() ); Assert.AreEqual( 1.2, obj2.ToDoubleOrNull() ); } /// <summary> /// 转换为高精度浮点数 /// </summary> [TestMethod] public void TestToDecimal() { string obj1 = ""; string obj2 = "1.2"; Assert.AreEqual( 0, obj1.ToDecimal() ); Assert.AreEqual( 1.2M, obj2.ToDecimal() ); } /// <summary> /// 转换为可空高精度浮点数 /// </summary> [TestMethod] public void TestToDecimalOrNull() { string obj1 = ""; string obj2 = "1.2"; Assert.IsNull( obj1.ToDecimalOrNull() ); Assert.AreEqual( 1.2M, obj2.ToDecimalOrNull() ); } /// <summary> /// 转换为日期 /// </summary> [TestMethod] public void TestToDate() { string obj1 = ""; string obj2 = "2000-1-1"; Assert.AreEqual( DateTime.MinValue, obj1.ToDate() ); Assert.AreEqual( new DateTime( 2000, 1, 1 ), obj2.ToDate() ); } /// <summary> /// 转换为可空日期 /// </summary> [TestMethod] public void TestToDateOrNull() { string obj1 = ""; string obj2 = "2000-1-1"; Assert.IsNull( obj1.ToDateOrNull() ); Assert.AreEqual( new DateTime( 2000, 1, 1 ), obj2.ToDateOrNull() ); } /// <summary> /// 转换为Guid /// </summary> [TestMethod] public void TestToGuid() { string obj1 = ""; string obj2 = "B9EB56E9-B720-40B4-9425-00483D311DDC"; Assert.AreEqual( Guid.Empty, obj1.ToGuid() ); Assert.AreEqual( new Guid( obj2 ), obj2.ToGuid() ); } /// <summary> /// 转换为可空Guid /// </summary> [TestMethod] public void TestToGuidOrNull() { string obj1 = ""; string obj2 = "B9EB56E9-B720-40B4-9425-00483D311DDC"; Assert.IsNull( obj1.ToGuidOrNull() ); Assert.AreEqual( new Guid( obj2 ), obj2.ToGuidOrNull() ); } /// <summary> /// 转换为Guid集合,值为字符串 /// </summary> [TestMethod] public void TestToGuidList_String() { const string guid = "83B0233C-A24F-49FD-8083-1337209EBC9A,,EAB523C6-2FE7-47BE-89D5-C6D440C3033A,"; Assert.AreEqual( 2, guid.ToGuidList().Count ); Assert.AreEqual( new Guid( "83B0233C-A24F-49FD-8083-1337209EBC9A" ), guid.ToGuidList()[0] ); Assert.AreEqual( new Guid( "EAB523C6-2FE7-47BE-89D5-C6D440C3033A" ), guid.ToGuidList()[1] ); } /// <summary> /// 转换为Guid集合,值为字符串集合 /// </summary> [TestMethod] public void TestToGuidList_StringList() { var list = new List<string> {"83B0233C-A24F-49FD-8083-1337209EBC9A", "EAB523C6-2FE7-47BE-89D5-C6D440C3033A"}; Assert.AreEqual( 2, list.ToGuidList().Count ); Assert.AreEqual( new Guid( "83B0233C-A24F-49FD-8083-1337209EBC9A" ), list.ToGuidList()[0] ); Assert.AreEqual( new Guid( "EAB523C6-2FE7-47BE-89D5-C6D440C3033A" ), list.ToGuidList()[1] ); } /// <summary> /// 转换为字符串 /// </summary> [TestMethod] public void TestToStr() { object value = null; Assert.AreEqual( string.Empty, value.ToStr() ); value = 1; Assert.AreEqual( "1", value.ToStr() ); } } }
在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 == 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应用程序框架公共操作类(一):数据类型转换公共操作类(介绍篇)
- Util应用程序框架公共操作类(十):可空值类型扩展
- Util应用程序框架公共操作类(九):Lambda表达式扩展
- Util应用程序框架公共操作类(六):验证扩展
- Util应用程序框架公共操作类(四):验证公共操作类
- Util应用程序框架公共操作类(五):异常公共操作类
- Util应用程序框架公共操作类(八):Lambda表达式公共操作类(二)
- Util应用程序框架公共操作类
- Util应用程序框架公共操作类(十一):表达式生成器
- Util应用程序框架公共操作类(十二):Lambda表达式公共操作类(三)
- Util应用程序框架公共操作类(七):Lambda表达式公共操作类
- easyui datetimebox处理【前台传递到后台是string类型,但是后台定义的是java.util.date,如何自动转换数据类型】
- 应用程序框架实战十二:公共操作类开发技巧(初学者必读)
- 应用程序框架实战三十四:数据传输对象(DTO)介绍及各类型实体比较(转)
- 基于Swift的iOS应用程序开发:字符串String与Data数据类型相互转换
- java数据类型转换____Gson框架对象和JSON转换
- 应用程序框架实战十二:公共操作类开发技巧(初学者必读)
- 应用程序框架实战三十四:数据传输对象(DTO)介绍及各类型实体比较
- java框架之struts2数据类型转换(2)
- 两个框架之间的数据类型转换,需要桥接技术