上一篇以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提供了一个扩展方法的语法,这是一个非常强大的功能,它通过静态方法的方式向目标类型添加一个模拟的实例方法。

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

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 = "";
Assert.AreEqual( , obj1.ToInt() );
Assert.AreEqual( , obj2.ToInt() );
} /// <summary>
/// 转换为可空整数
/// </summary>
[TestMethod]
public void TestToIntOrNull() {
string obj1 = "";
string obj2 = "";
Assert.IsNull( obj1.ToIntOrNull() );
Assert.AreEqual( , obj2.ToIntOrNull() );
} /// <summary>
/// 转换为双精度浮点数
/// </summary>
[TestMethod]
public void TestToDouble() {
string obj1 = "";
string obj2 = "1.2";
Assert.AreEqual( , 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( , 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( , , ), obj2.ToDate() );
} /// <summary>
/// 转换为可空日期
/// </summary>
[TestMethod]
public void TestToDateOrNull() {
string obj1 = "";
string obj2 = "2000-1-1";
Assert.IsNull( obj1.ToDateOrNull() );
Assert.AreEqual( new DateTime( , , ), 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( , guid.ToGuidList().Count );
Assert.AreEqual( new Guid( "83B0233C-A24F-49FD-8083-1337209EBC9A" ), guid.ToGuidList()[] );
Assert.AreEqual( new Guid( "EAB523C6-2FE7-47BE-89D5-C6D440C3033A" ), guid.ToGuidList()[] );
} /// <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( , list.ToGuidList().Count );
Assert.AreEqual( new Guid( "83B0233C-A24F-49FD-8083-1337209EBC9A" ), list.ToGuidList()[] );
Assert.AreEqual( new Guid( "EAB523C6-2FE7-47BE-89D5-C6D440C3033A" ), list.ToGuidList()[] );
} /// <summary>
/// 转换为字符串
/// </summary>
[TestMethod]
public void TestToStr() {
object value = null;
Assert.AreEqual( string.Empty, value.ToStr() );
value = ;
Assert.AreEqual( "", 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应用程序框架公共操作类(三):数据类型转换公共操作类(扩展篇)的更多相关文章

  1. Util应用程序框架公共操作类(二):数据类型转换公共操作类(源码篇)

    上一篇介绍了数据类型转换的一些情况,可以看出,如果不进行封装,有可能导致比较混乱的代码.本文通过TDD方式把数据类型转换公共操作类开发出来,并提供源码下载. 我们在 应用程序框架实战十一:创建VS解决 ...

  2. Util应用程序框架公共操作类

    随笔分类 - Util应用程序框架公共操作类 Util应用程序框架公共操作类 Util应用程序框架公共操作类(五):异常公共操作类 摘要: 任何系统都需要处理错误,本文介绍的异常公共操作类,用于对业务 ...

  3. Util应用程序框架公共操作类(十二):Lambda表达式公共操作类(三)

    今天在开发一个简单查询时,发现我的Lambda操作类的GetValue方法无法正确获取枚举类型值,以至查询结果错误. 我增加了几个单元测试来捕获错误,代码如下. /// <summary> ...

  4. Util应用程序框架公共操作类(四):验证公共操作类

    为了能够验证领域实体,需要一个验证公共操作类来提供支持.由于我将使用企业库(Enterprise Library)的验证组件来完成这项任务,所以本文也将演示对第三方框架的封装要点. .Net提供了一个 ...

  5. Util应用程序框架公共操作类(七):Lambda表达式公共操作类

    前一篇扩展了两个常用验证方法,本文将封装两个Lambda表达式操作,用来为下一篇的查询扩展服务. Lambda表达式是一种简洁的匿名函数语法,可以用它将方法作为委托参数传递.在Linq中,大量使用La ...

  6. Util应用程序框架公共操作类(一):数据类型转换公共操作类(介绍篇)

    本系列文章将介绍一些对初学者有帮助的辅助类,这些辅助类本身并没有什么稀奇之处,如何能发现需要封装它们可能更加重要,所谓授之以鱼不如授之以渔,掌握封装公共操作类的技巧才是关键,我会详细说明创建这些类的动 ...

  7. YTU 2618: B 求类中数据成员的最大值-类模板

    2618: B 求类中数据成员的最大值-类模板 时间限制: 1 Sec  内存限制: 128 MB 提交: 430  解决: 300 题目描述 声明一个类模板,类模板中有三个相同类型的数据成员,有一函 ...

  8. 泛型集合、datatable常用数据类型转换Json帮助类

    泛型集合.datatable常用数据类型转换Json帮助类 using System; using System.Data; using System.Configuration; using Sys ...

  9. Unity3d通用工具类之数据配置加载类-ini配置文件加载

    Unity3d通用工具类之数据配置加载类-ini配置文件加载 上次我们讲过xml文件的加载配置管理,今天我们换个配置文件,也是比较常见的配置文件.ini格式的数据. 按照国际管理先贴一张啥是.ini文 ...

随机推荐

  1. WCF服务编程

    WCF服务编程, 我是WCF的初学者,在这想分享学习WCF服务编程的过程,欢迎大家多多指教!

  2. Redis_密码管理(转)

    一. 如何初始化redis的密码? 总共2个步骤: a.在配置文件中有个参数: requirepass  这个就是配置redis访问密码的参数. 比如 requirepass test123 b.配置 ...

  3. 《JavaScript高级程序设计(第3版)》阅读总结记录第一章之JavaScript简介

    前言: 为什么会想到把<JavaScript 高级程序设计(第 3 版)>总结记录呢,之前写过一篇博客,研究的轮播效果,后来又去看了<JavaScript 高级程序设计(第3版)&g ...

  4. ssh简化后之事务管理

    为了能让大家更好的了解,所以今天跟大家分享整个项目.ps:ssh环境的搭建我就不一一讲解了,请大家参考 http://www.cnblogs.com/zczc1996/p/5842367.html. ...

  5. 在React 组件中使用Echarts

    在完成一个需求的时候碰到一个场景需要使用柱状图.涉及到可视化,第一反应当然是Echarts了.平时用js加载Echarts组件很方便,但是在React中就要费下神了.各种连蒙带猜实现了.edmo里的E ...

  6. Oracle CDC配置案例

    异步部署 1. 环境的配置准备 1.1.    数据库版本 SQL> select * from v$version; BANNER ------------------------------ ...

  7. 关于PHP中<?php ?>的结束标签是否添加

    在纯PHP代码中“?>”结束标签最好不要添加 原因:容易导致输出多余的空白或者换行,以及由此产生的一些报错. 比如a.php文件中,在?>标签后面多出空格或者换行,而当b.php文件引入a ...

  8. EditPlus快捷键

    Editplus 选中一行: ctrl+rEditplus 复制一行: ctrl+r选择行,然后ctrl+c复制.复制一行到下一行中:Editplus有:Ctrl+j 复制上一行的一个字符到当前行Ed ...

  9. 整理一自己不怎么熟悉的HTML标签(会陆续更新)

    ---恢复内容开始--- 小白刚开始接触HTML和CSS,在学习过程中发现又遇到很多不认识的标签,于是就想把他们都记录下来,一来可加深记忆,二来也方便以后查阅,当然如果能帮助到你们也是很开心的啦! 1 ...

  10. poj1200-Crazy Search(hash入门经典)

    Hash:一般是一个整数.就是说通过某种算法,可以把一个字符串"压缩" 成一个整数.一,题意: 给出两个数n,nc,并给出一个由nc种字符组成的字符串.求这个字符串中长度为n的不同 ...