博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Util应用程序框架公共操作类(二):数据类型转换公共操作类(源码篇)
阅读量:7077 次
发布时间:2019-06-28

本文共 36014 字,大约阅读时间需要 120 分钟。

  上一篇介绍了数据类型转换的一些情况,可以看出,如果不进行封装,有可能导致比较混乱的代码。本文通过TDD方式把数据类型转换公共操作类开发出来,并提供源码下载。

  我们在 应用程序框架实战十一:创建VS解决方案与程序集 一文已经创建了解决方案,包含一个类库项目和一个单元测试项目。单元测试将使用.Net自带的 MsTest,另外通过Resharper工具来观察测试结果。

  首先考虑我们期望的API长成什么样子。基于TDD开发,其中一个作用是帮助程序员设计期望的API,这称为意图导向编程。

  因为数据类型转换是Convert,所以我们先在单元测试项目中创建一个ConvertTest的类文件。 

  类创建好以后,我先随便创建一个方法Test,以迅速展开工作。测试的方法名Test,我是随便起的,因为现在还不清楚API是什么样,我一会再回过头来改。

using Microsoft.VisualStudio.TestTools.UnitTesting;namespace Util.Tests {    ///     /// 类型转换公共操作类测试    ///     [TestClass]    public class ConvertTest {        [TestMethod]        public void Test() {        }    }}

  为了照顾还没有使用单元测试的朋友,我在这里简单介绍一下MsTest。MsTest是.Net仿照JUnit打造的一个单元测试框架。在单元测试类上需要添加一个TestClass特性,在测试方法上添加TestMethod特性,用来识别哪些类的操作需要测试。还有一些其它特性,在用到的时候我再介绍。

  现在先来实现一个最简单的功能,把字符串”1”转换为整数1。

[TestMethod]public void Test() {    Assert.AreEqual( 1, Util.ConvertHelper.ToInt( "1" ) );}

  我把常用公共操作类尽量放到顶级命名空间Util,这样我就可以通过编写Util.来弹出代码提示,这样我连常用类也不用记了。

  使用ConvertHelper是一个常规命名,大多数开发人员可以理解它是一个类型转换的公共操作类。我也这样用了多年,不过后面我发现Util.ConvertHelper有点啰嗦,所以我简化成Util.Convert,但Convert又和系统重名了,所以我现在使用Util.Conv,你不一定要按我的这个命名,你可以使用ConvertHelper这样的命名以提高代码清晰度。

  System.Convert使用ToInt32来精确表示int是一个32位的数字,不过我们的公共操作类不用这样精确,ToInt就可以了,如果要封装ToInt64呢,我就用ToLong,这样比较符合我的习惯。

  现在代码被简化成了下面的代码。

Assert.AreEqual( 1, Util.Conv.ToInt( "1" ) );

  Assert在测试中用来断言,断言就是比较实际计算出来的值是否和预期一致,Assert包含大量比较方法,AreEqual使用频率最高,用来比较预期值(左边)与实际值(右边)是否值相等,还有一个AreSame方法用来比较是否引用相等。   

    

  由于Conv类还未创建,所以显示一个红色警告。   现在在Util类库项目中创建一个Conv类。

  创建了Conv类以后,单元测试代码检测到Conv,但ToInt方法未创建,所以红色警告转移到ToInt方法。

  现在用鼠标左键单击红色ToInit方法,Resharper在左侧显示一个红色的灯泡。

  单击红色灯泡提示,选择第一项”Create Method ‘Conv.ToInt’”。

  Resharper会在Conv类中自动创建一个ToInt方法。

public class Conv {    public static int ToInt( string s ) {        throw new NotImplementedException();     }}

  方法体抛出一个未实现的异常,这正是我们想要的。TDD的口诀是“红、绿、重构”,第一步需要先保证方法执行失败,显示红色警告。至于未何需要测试先行,以及首先执行失败,牵扯TDD开发价值观,请大家参考相关资料。

  准备工作已经就绪,现在可以运行测试了。安装了Resharper以后,在添加了TestClass特性的左侧,会看见两个重叠在一起的圆形图标。另外,在TestMethod特性左侧,有一个黑白相间的圆形图标。

   单击Test方法左侧的图标,然后点击Run按钮。如果单击TestClass特性左侧的图标,会运行该类所有测试。

  测试开始运行,并显示红色警告,提示未实现的异常,第一步完成。

  为了实现功能,现在来添加ToInt方法的代码。

public static int ToInt( string s ) {    int result;    int.TryParse( s, out result );    return result;}

  再次运行测试,已经能够成功通过,第二步完成。 

  第三步是进行重构,现在看哪些地方可以重构。参数s看起来有点不爽,改成data,并添加XML注释。

///         /// 转换为整型        ///         /// 数据        public static int ToInt( string data ) {            int result;            int.TryParse( data, out result );            return result;        }

  另外重构一下测试,为了更容易找到相关测试,一般测试文件名使用类名+Test,现在测试文件名改成ConvTest.cs,测试类名改成ConvTest。把测试方法名改成TestToInt,并添加XML注释。

///         /// 测试转换为整型        ///         [TestMethod]        public void TestToInt() {            Assert.AreEqual( 1, Util.Conv.ToInt( "1" ) );        }

  关于测试的命名,很多著作都提出了自己不同的方法。在《.Net单元测试艺术》中,作者建议使用三部分进行组合命名。还有一些著作建议将测试内容用下划线分隔单词,拼成一个长句子,以方便阅读和理解。这可能对英文水平好的人很有效,不过我的英文水平很烂,我拿一些单词拼成一个长句以后,发现更难理解了。所以我所采用的测试方法命名可能不一定好,你可以按你容易理解的方式来命名。

  重构之后,需要重新测试代码,以观察是否导致失败。

  上面简单介绍了TDD的一套开发流程,主要为了照顾还没有体验过单元测试的人,后面直接粘贴代码,以避免这样低效的叙述方式。

  单元测试代码如下。

1 using System;  2 using Microsoft.VisualStudio.TestTools.UnitTesting;  3   4 namespace Util.Tests {  5     ///   6     /// 类型转换公共操作类测试  7     ///   8     [TestClass]  9     public class ConvTest { 10  11         #region ToInt(转换为整型) 12  13         ///  14         ///转换为整型,值为null 15         /// 16         [TestMethod] 17         public void TestToInt_Null() { 18             Assert.AreEqual( 0, Util.Conv.ToInt( null ) ); 19         } 20  21         ///  22         ///转换为整型,值为空字符串 23         /// 24         [TestMethod] 25         public void TestToInt_Empty() { 26             Assert.AreEqual( 0, Util.Conv.ToInt( "" ) ); 27         } 28  29         ///  30         ///转换为整型,无效值 31         /// 32         [TestMethod] 33         public void TestToInt_Invalid() { 34             Assert.AreEqual( 0, Util.Conv.ToInt( "1A" ) ); 35         } 36  37         ///  38         ///转换为整型,有效值 39         /// 40         [TestMethod] 41         public void TestToInt() { 42             Assert.AreEqual( 1, Util.Conv.ToInt( "1" ) ); 43             Assert.AreEqual( 1778020, Util.Conv.ToInt( "1778019.7801684" ) ); 44         } 45  46         #endregion 47  48         #region ToIntOrNull(转换为可空整型) 49  50         ///  51         ///转换为可空整型,值为null 52         /// 53         [TestMethod] 54         public void TestToIntOrNull_Null() { 55             Assert.IsNull( Util.Conv.ToIntOrNull( null ) ); 56         } 57  58         ///  59         ///转换为可空整型,值为空字符串 60         /// 61         [TestMethod] 62         public void TestToIntOrNull_Empty() { 63             Assert.IsNull( Util.Conv.ToIntOrNull( "" ) ); 64         } 65  66         ///  67         ///转换为可空整型,无效值 68         /// 69         [TestMethod] 70         public void TestToIntOrNull_Invalid() { 71             Assert.IsNull( Util.Conv.ToIntOrNull( "1A" ) ); 72         } 73  74         ///  75         ///转换为可空整型,值为0 76         /// 77         [TestMethod] 78         public void TestToIntOrNull_0() { 79             Assert.AreEqual( 0, Util.Conv.ToIntOrNull( "0" ) ); 80         } 81  82         ///  83         ///转换为可空整型,有效值 84         /// 85         [TestMethod] 86         public void TestToIntOrNull() { 87             Assert.AreEqual( 1, Util.Conv.ToIntOrNull( "1" ) ); 88         } 89  90         #endregion 91  92         #region ToDouble(转换为双精度浮点数) 93  94         ///  95         ///转换为双精度浮点数,值为null 96         /// 97         [TestMethod] 98         public void TestToDouble_Null() { 99             Assert.AreEqual( 0, Util.Conv.ToDouble( null ) );100         }101 102         /// 103         ///转换为双精度浮点数,值为空字符串104         ///105         [TestMethod]106         public void TestToDouble_Empty() {107             Assert.AreEqual( 0, Util.Conv.ToDouble( "" ) );108         }109 110         /// 111         ///转换为双精度浮点数,无效值112         ///113         [TestMethod]114         public void TestToDouble_Invalid() {115             Assert.AreEqual( 0, Util.Conv.ToDouble( "1A" ) );116         }117 118         /// 119         ///转换为双精度浮点数,有效值120         ///121         [TestMethod]122         public void TestToDouble() {123             Assert.AreEqual( 1.2, Util.Conv.ToDouble( "1.2" ) );124         }125 126         /// 127         /// 转换为双精度浮点数,指定2位小数位数128         ///129         [TestMethod()]130         public void TestToDouble_DigitsIs2() {131             Assert.AreEqual( 12.36, Util.Conv.ToDouble( "12.355", 2 ) );132         }133 134         #endregion135 136         #region ToDoubleOrNull(转换为可空双精度浮点数)137 138         /// 139         ///转换为可空双精度浮点数,值为null140         ///141         [TestMethod]142         public void TestToDoubleOrNull_Null() {143             Assert.IsNull( Util.Conv.ToDoubleOrNull( null ) );144         }145 146         /// 147         ///转换为可空双精度浮点数,值为空字符串148         ///149         [TestMethod]150         public void TestToDoubleOrNull_Empty() {151             Assert.IsNull( Util.Conv.ToDoubleOrNull( "" ) );152         }153 154         /// 155         ///转换为可空双精度浮点数,无效值156         ///157         [TestMethod]158         public void TestToDoubleOrNull_Invalid() {159             Assert.IsNull( Util.Conv.ToDoubleOrNull( "1A" ) );160         }161 162         /// 163         ///转换为可空双精度浮点数,值为0164         ///165         [TestMethod]166         public void TestToDoubleOrNull_0() {167             Assert.AreEqual( 0, Util.Conv.ToDoubleOrNull( "0" ) );168         }169 170         /// 171         ///转换为可空双精度浮点数,有效值172         ///173         [TestMethod]174         public void TestToDoubleOrNull() {175             Assert.AreEqual( 1.2, Util.Conv.ToDoubleOrNull( "1.2" ) );176         }177 178         #endregion179 180         #region ToDecimal(转换为高精度浮点数)181 182         /// 183         ///转换为高精度浮点数,值为null184         ///185         [TestMethod]186         public void TestToDecimal_Null() {187             Assert.AreEqual( 0, Util.Conv.ToDecimal( null ) );188         }189 190         /// 191         ///转换为高精度浮点数,值为空字符串192         ///193         [TestMethod]194         public void TestToDecimal_Empty() {195             Assert.AreEqual( 0, Util.Conv.ToDecimal( "" ) );196         }197 198         /// 199         ///转换为高精度浮点数,无效值200         ///201         [TestMethod]202         public void TestToDecimal_Invalid() {203             Assert.AreEqual( 0, Util.Conv.ToDecimal( "1A" ) );204         }205 206         /// 207         ///转换为高精度浮点数,有效值208         ///209         [TestMethod]210         public void TestToDecimal() {211             Assert.AreEqual( 1.2M, Util.Conv.ToDecimal( "1.2" ) );212         }213 214         /// 215         /// 转换为高精度浮点数,指定2位小数位数216         ///217         [TestMethod()]218         public void TestToDecimal_DigitsIs2() {219             Assert.AreEqual( 12.24M, Util.Conv.ToDecimal( "12.235", 2 ) );220         }221 222         #endregion223 224         #region ToDecimalOrNull(转换为可空高精度浮点数)225 226         /// 227         ///转换为可空高精度浮点数,值为null228         ///229         [TestMethod]230         public void TestToDecimalOrNull_Null() {231             Assert.IsNull( Util.Conv.ToDecimalOrNull( null ) );232         }233 234         /// 235         ///转换为可空高精度浮点数,值为空字符串236         ///237         [TestMethod]238         public void TestToDecimalOrNull_Empty() {239             Assert.IsNull( Util.Conv.ToDecimalOrNull( "" ) );240         }241 242         /// 243         ///转换为可空高精度浮点数,无效值244         ///245         [TestMethod]246         public void TestToDecimalOrNull_Invalid() {247             Assert.IsNull( Util.Conv.ToDecimalOrNull( "1A" ) );248         }249 250         /// 251         ///转换为可空高精度浮点数,无效值,指定2位小数位数252         ///253         [TestMethod]254         public void TestToDecimalOrNull_Invalid_DigitsIs2() {255             Assert.IsNull( Util.Conv.ToDecimalOrNull( "1A", 2 ) );256         }257 258         /// 259         ///转换为可空高精度浮点数,值为0260         ///261         [TestMethod]262         public void TestToDecimalOrNull_0() {263             Assert.AreEqual( 0, Util.Conv.ToDecimalOrNull( "0" ) );264         }265 266         /// 267         ///转换为可空高精度浮点数,有效值268         ///269         [TestMethod]270         public void TestToDecimalOrNull() {271             Assert.AreEqual( 1.2M, Util.Conv.ToDecimalOrNull( "1.2" ) );272         }273 274         /// 275         /// 转换为可空高精度浮点数,指定2位小数位数276         ///277         [TestMethod()]278         public void ToDecimalOrNull_DigitsIs2() {279             Assert.AreEqual( 12.24M, Util.Conv.ToDecimalOrNull( "12.235", 2 ) );280         }281 282         #endregion283 284         #region ToGuid(转换为Guid)285 286         /// 287         ///转换为Guid,值为null288         ///289         [TestMethod]290         public void TestToGuid_Null() {291             Assert.AreEqual( Guid.Empty, Util.Conv.ToGuid( null ) );292         }293 294         /// 295         ///转换为Guid,值为空字符串296         ///297         [TestMethod]298         public void TestToGuid_Empty() {299             Assert.AreEqual( Guid.Empty, Util.Conv.ToGuid( "" ) );300         }301 302         /// 303         ///转换为Guid,无效值304         ///305         [TestMethod]306         public void TestToGuid_Invalid() {307             Assert.AreEqual( Guid.Empty, Util.Conv.ToGuid( "1A" ) );308         }309 310         /// 311         ///转换为Guid,有效值312         ///313         [TestMethod]314         public void TestToGuid() {315             Assert.AreEqual( new Guid( "B9EB56E9-B720-40B4-9425-00483D311DDC" ), Util.Conv.ToGuid( "B9EB56E9-B720-40B4-9425-00483D311DDC" ) );316         }317 318         #endregion319 320         #region ToGuidOrNull(转换为可空Guid)321 322         /// 323         ///转换为可空Guid,值为null324         ///325         [TestMethod]326         public void TestToGuidOrNull_Null() {327             Assert.IsNull( Util.Conv.ToGuidOrNull( null ) );328         }329 330         /// 331         ///转换为可空Guid,值为空字符串332         ///333         [TestMethod]334         public void TestToGuidOrNull_Empty() {335             Assert.IsNull( Util.Conv.ToGuidOrNull( "" ) );336         }337 338         /// 339         ///转换为可空Guid,无效值340         ///341         [TestMethod]342         public void TestToGuidOrNull_Invalid() {343             Assert.IsNull( Util.Conv.ToGuidOrNull( "1A" ) );344         }345 346         /// 347         ///转换为可空Guid,有效值348         ///349         [TestMethod]350         public void TestToGuidOrNull() {351             Assert.AreEqual( new Guid( "B9EB56E9-B720-40B4-9425-00483D311DDC" ), Util.Conv.ToGuidOrNull( "B9EB56E9-B720-40B4-9425-00483D311DDC" ) );352         }353 354         #endregion355 356         #region ToGuidList(转换为Guid集合)357 358         /// 359         /// 转换为Guid集合,验证空字符串360         /// 361         [TestMethod]362         public void TestToGuidList_Empty() {363             Assert.AreEqual( 0, Util.Conv.ToGuidList( "" ).Count );364         }365 366         /// 367         /// 转换为Guid集合,验证最后为逗号368         /// 369         [TestMethod]370         public void TestToGuidList_LastIsComma() {371             Assert.AreEqual( 1, Util.Conv.ToGuidList( "83B0233C-A24F-49FD-8083-1337209EBC9A," ).Count );372         }373 374         /// 375         /// 转换为Guid集合,验证中间包含逗号376         /// 377         [TestMethod]378         public void TestToGuidList_MiddleIsComma() {379             const string guid = "83B0233C-A24F-49FD-8083-1337209EBC9A,,EAB523C6-2FE7-47BE-89D5-C6D440C3033A,";380             Assert.AreEqual( 2, Util.Conv.ToGuidList( guid ).Count );381             Assert.AreEqual( new Guid( "83B0233C-A24F-49FD-8083-1337209EBC9A" ), Util.Conv.ToGuidList( guid )[0] );382             Assert.AreEqual( new Guid( "EAB523C6-2FE7-47BE-89D5-C6D440C3033A" ), Util.Conv.ToGuidList( guid )[1] );383         }384 385         /// 386         /// 转换为Guid集合,仅1个Guid387         /// 388         [TestMethod]389         public void TestToGuidList_1Guid() {390             const string guid = "83B0233C-A24F-49FD-8083-1337209EBC9A";391             Assert.AreEqual( 1, Util.Conv.ToGuidList( guid ).Count );392             Assert.AreEqual( new Guid( guid ), Util.Conv.ToGuidList( guid )[0] );393         }394 395         /// 396         /// 转换为Guid集合,2个Guid397         /// 398         [TestMethod]399         public void TestToGuidList_2Guid() {400             const string guid = "83B0233C-A24F-49FD-8083-1337209EBC9A,EAB523C6-2FE7-47BE-89D5-C6D440C3033A";401             Assert.AreEqual( 2, Util.Conv.ToGuidList( guid ).Count );402             Assert.AreEqual( new Guid( "83B0233C-A24F-49FD-8083-1337209EBC9A" ), Util.Conv.ToGuidList( guid )[0] );403             Assert.AreEqual( new Guid( "EAB523C6-2FE7-47BE-89D5-C6D440C3033A" ), Util.Conv.ToGuidList( guid )[1] );404         }405 406         #endregion407 408         #region ToDate(转换为日期)409 410         /// 411         ///转换为日期,值为null412         ///413         [TestMethod]414         public void TestToDate_Null() {415             Assert.AreEqual( DateTime.MinValue, Util.Conv.ToDate( null ) );416         }417 418         /// 419         ///转换为日期,值为空字符串420         ///421         [TestMethod]422         public void TestToDate_Empty() {423             Assert.AreEqual( DateTime.MinValue, Util.Conv.ToDate( "" ) );424         }425 426         /// 427         ///转换为日期,无效值428         ///429         [TestMethod]430         public void TestToDate_Invalid() {431             Assert.AreEqual( DateTime.MinValue, Util.Conv.ToDate( "1A" ) );432         }433 434         /// 435         ///转换为日期,有效值436         ///437         [TestMethod]438         public void TestToDate() {439             Assert.AreEqual( new DateTime( 2000, 1, 1 ), Util.Conv.ToDate( "2000-1-1" ) );440         }441 442         #endregion443 444         #region ToDateOrNull(转换为可空日期)445 446         /// 447         ///转换为可空日期,值为null448         ///449         [TestMethod]450         public void TestToDateOrNull_Null() {451             Assert.IsNull( Util.Conv.ToDateOrNull( null ) );452         }453 454         /// 455         ///转换为可空日期,值为空字符串456         ///457         [TestMethod]458         public void TestToDateOrNull_Empty() {459             Assert.IsNull( Util.Conv.ToDateOrNull( "" ) );460         }461 462         /// 463         ///转换为可空日期,无效值464         ///465         [TestMethod]466         public void TestToDateOrNull_Invalid() {467             Assert.IsNull( Util.Conv.ToDateOrNull( "1A" ) );468         }469 470         /// 471         ///转换为可空日期,有效值472         ///473         [TestMethod]474         public void TestToDateOrNull() {475             Assert.AreEqual( new DateTime( 2000, 1, 1 ), Util.Conv.ToDateOrNull( "2000-1-1" ) );476         }477 478         #endregion479 480         #region ToBool(转换为布尔值)481 482         /// 483         ///转换为布尔值,值为null484         ///485         [TestMethod]486         public void TestToBool_Null() {487             Assert.AreEqual( false, Util.Conv.ToBool( null ) );488         }489 490         /// 491         ///转换为布尔值,值为空字符串492         ///493         [TestMethod]494         public void TestToBool_Empty() {495             Assert.AreEqual( false, Util.Conv.ToBool( "" ) );496         }497 498         /// 499         ///转换为布尔值,无效值500         ///501         [TestMethod]502         public void TestToBool_Invalid() {503             Assert.AreEqual( false, Util.Conv.ToBool( "1A" ) );504         }505 506         /// 507         ///转换为布尔值,值为False508         ///509         [TestMethod]510         public void TestToBool_False() {511             Assert.AreEqual( false, Util.Conv.ToBool( "0" ) );512             Assert.AreEqual( false, Util.Conv.ToBool( "否" ) );513             Assert.AreEqual( false, Util.Conv.ToBool( "no" ) );514             Assert.AreEqual( false, Util.Conv.ToBool( "No" ) );515             Assert.AreEqual( false, Util.Conv.ToBool( "false" ) );516             Assert.AreEqual( false, Util.Conv.ToBool( "False" ) );517         }518 519         /// 520         ///转换为布尔值,值为True521         ///522         [TestMethod]523         public void TestToBool_True() {524             Assert.AreEqual( true, Util.Conv.ToBool( "1" ) );525             Assert.AreEqual( true, Util.Conv.ToBool( "是" ) );526             Assert.AreEqual( true, Util.Conv.ToBool( "yes" ) );527             Assert.AreEqual( true, Util.Conv.ToBool( "Yes" ) );528             Assert.AreEqual( true, Util.Conv.ToBool( "true" ) );529             Assert.AreEqual( true, Util.Conv.ToBool( "True" ) );530         }531 532         #endregion533 534         #region ToBoolOrNull(转换为可空布尔值)535 536         /// 537         ///转换为可空布尔值,值为null538         ///539         [TestMethod]540         public void TestToBoolOrNull_Null() {541             Assert.IsNull( Util.Conv.ToBoolOrNull( null ) );542         }543 544         /// 545         ///转换为可空布尔值,值为空字符串546         ///547         [TestMethod]548         public void TestToBoolOrNull_Empty() {549             Assert.IsNull( Util.Conv.ToBoolOrNull( "" ) );550         }551 552         /// 553         ///转换为可空布尔值,无效值554         ///555         [TestMethod]556         public void TestToBoolOrNull_Invalid() {557             Assert.IsNull( Util.Conv.ToBoolOrNull( "1A" ) );558         }559 560         /// 561         ///转换为布尔值,值为False562         ///563         [TestMethod]564         public void TestToBoolOrNull_False() {565             Assert.AreEqual( false, Util.Conv.ToBoolOrNull( "0" ) );566             Assert.AreEqual( false, Util.Conv.ToBoolOrNull( "否" ) );567             Assert.AreEqual( false, Util.Conv.ToBoolOrNull( "no" ) );568             Assert.AreEqual( false, Util.Conv.ToBoolOrNull( "No" ) );569             Assert.AreEqual( false, Util.Conv.ToBoolOrNull( "false" ) );570             Assert.AreEqual( false, Util.Conv.ToBoolOrNull( "False" ) );571         }572 573         /// 574         ///转换为布尔值,值为True575         ///576         [TestMethod]577         public void TestToBoolOrNull_True() {578             Assert.AreEqual( true, Util.Conv.ToBoolOrNull( "1" ) );579             Assert.AreEqual( true, Util.Conv.ToBoolOrNull( "是" ) );580             Assert.AreEqual( true, Util.Conv.ToBoolOrNull( "yes" ) );581             Assert.AreEqual( true, Util.Conv.ToBoolOrNull( "Yes" ) );582             Assert.AreEqual( true, Util.Conv.ToBoolOrNull( "true" ) );583             Assert.AreEqual( true, Util.Conv.ToBoolOrNull( "True" ) );584         }585 586         #endregion587 588         #region ToString(转换为字符串)589 590         /// 591         ///转换为字符串,值为null592         ///593         [TestMethod]594         public void TestToString_Null() {595             Assert.AreEqual( string.Empty, Util.Conv.ToString( null ) );596         }597 598         /// 599         ///转换为字符串,值为空字符串600         ///601         [TestMethod]602         public void TestToString_Empty() {603             Assert.AreEqual( string.Empty, Util.Conv.ToString( " " ) );604         }605 606         /// 607         ///转换为字符串,有效值608         ///609         [TestMethod]610         public void TestToString() {611             Assert.AreEqual( "1", Util.Conv.ToString( 1 ) );612         }613 614         #endregion615 616         #region To(通用泛型转换)617 618         #region 目标为int619 620         /// 621         ///通用泛型转换,目标为整数,值为null622         ///623         [TestMethod]624         public void TestTo_Int_Null() {625             Assert.AreEqual( 0, Conv.To
( null ) );626 }627 628 ///
629 ///通用泛型转换,目标为整数,值为空字符串630 ///631 [TestMethod]632 public void TestTo_Int_Empty() {633 Assert.AreEqual( 0, Conv.To
( "" ) );634 }635 636 ///
637 ///通用泛型转换,目标为整数,无效值638 ///639 [TestMethod]640 public void TestTo_Int_Invalid() {641 Assert.AreEqual( 0, Conv.To
( "1A" ) );642 }643 644 ///
645 ///通用泛型转换,目标为整数,有效值646 ///647 [TestMethod]648 public void TestTo_Int() {649 Assert.AreEqual( 1, Conv.To
( "1" ) );650 }651 652 ///
653 ///通用泛型转换,目标为可空整数,无效值654 ///655 [TestMethod]656 public void TestTo_IntOrNull_Invalid() {657 Assert.IsNull( Conv.To
( "1A" ) );658 }659 660 ///
661 ///通用泛型转换,目标为可空整数,有效值662 ///663 [TestMethod]664 public void TestTo_IntOrNull() {665 Assert.AreEqual( 1, Conv.To
( "1" ) );666 }667 668 #endregion669 670 #region 目标为Guid671 672 ///
673 ///通用泛型转换,目标为Guid,无效值674 ///675 [TestMethod]676 public void TestTo_Guid_Invalid() {677 Assert.AreEqual( Guid.Empty, Conv.To
( "1A" ) );678 }679 680 ///
681 ///通用泛型转换,目标为Guid,有效值682 ///683 [TestMethod]684 public void TestTo_Guid() {685 Assert.AreEqual( new Guid( "B9EB56E9-B720-40B4-9425-00483D311DDC" ),686 Conv.To
( "B9EB56E9-B720-40B4-9425-00483D311DDC" ) );687 }688 689 ///
690 ///通用泛型转换,目标为可空Guid,无效值691 ///692 [TestMethod]693 public void TestTo_GuidOrNull_Invalid() {694 Assert.IsNull( Conv.To
( "1A" ) );695 }696 697 ///
698 ///通用泛型转换,目标为可空Guid,有效值699 ///700 [TestMethod]701 public void TestTo_GuidOrNull() {702 Assert.AreEqual( new Guid( "B9EB56E9-B720-40B4-9425-00483D311DDC" ),703 Conv.To
( "B9EB56E9-B720-40B4-9425-00483D311DDC" ) );704 }705 706 #endregion707 708 #region 目标为string709 710 ///
711 ///通用泛型转换,目标为string,有效值712 ///713 [TestMethod]714 public void TestTo_String() {715 Assert.AreEqual( "123", Conv.To
( 123 ) );716 }717 718 #endregion719 720 #region 目标为double721 722 ///
723 ///通用泛型转换,目标为double,无效值724 ///725 [TestMethod]726 public void TestTo_Double_Invalid() {727 Assert.AreEqual( 0, Conv.To
( "1A" ) );728 }729 730 ///
731 ///通用泛型转换,目标为double,有效值732 ///733 [TestMethod]734 public void TestTo_Double() {735 Assert.AreEqual( 12.5, Conv.To
( "12.5" ) );736 }737 738 ///
739 ///通用泛型转换,目标为可空double,无效值740 ///741 [TestMethod]742 public void TestTo_DoubleOrNull_Invalid() {743 Assert.IsNull( Conv.To
( "1A" ) );744 }745 746 ///
747 ///通用泛型转换,目标为可空double,有效值748 ///749 [TestMethod]750 public void TestTo_DoubleOrNull() {751 Assert.AreEqual( 12.5, Conv.To
( "12.5" ) );752 }753 754 #endregion755 756 #region 目标为decimal757 758 ///
759 ///通用泛型转换,目标为decimal,无效值760 ///761 [TestMethod]762 public void TestTo_Decimal_Invalid() {763 Assert.AreEqual( 0, Conv.To
( "1A" ) );764 }765 766 ///
767 ///通用泛型转换,目标为decimal,有效值768 ///769 [TestMethod]770 public void TestTo_Decimal() {771 Assert.AreEqual( 12.5M, Conv.To
( "12.5" ) );772 }773 774 ///
775 ///通用泛型转换,目标为可空decimal,无效值776 ///777 [TestMethod]778 public void TestTo_DecimalOrNull_Invalid() {779 Assert.IsNull( Conv.To
( "1A" ) );780 }781 782 ///
783 ///通用泛型转换,目标为可空decimal,有效值784 ///785 [TestMethod]786 public void TestTo_DecimalOrNull() {787 Assert.AreEqual( 12.5M, Conv.To
( "12.5" ) );788 }789 790 #endregion791 792 #region 目标为bool793 794 ///
795 ///通用泛型转换,目标为bool,无效值796 ///797 [TestMethod]798 public void TestTo_Bool_Invalid() {799 Assert.AreEqual( false, Conv.To
( "1A" ) );800 }801 802 ///
803 ///通用泛型转换,目标为bool,有效值804 ///805 [TestMethod]806 public void TestTo_Bool() {807 Assert.AreEqual( true, Conv.To
( 1 ) );808 }809 810 ///
811 ///通用泛型转换,目标为可空bool,无效值812 ///813 [TestMethod]814 public void TestTo_BoolOrNull_Invalid() {815 Assert.IsNull( Conv.To
( "1A" ) );816 }817 818 ///
819 ///通用泛型转换,目标为可空bool,有效值820 ///821 [TestMethod]822 public void TestTo_BoolOrNull() {823 Assert.AreEqual( true, Conv.To
( "true" ) );824 }825 826 #endregion827 828 #region 目标为DateTime829 830 ///
831 ///通用泛型转换,目标为DateTime,无效值832 ///833 [TestMethod]834 public void TestTo_DateTime_Invalid() {835 Assert.AreEqual( DateTime.MinValue, Conv.To
( "1A" ) );836 }837 838 ///
839 ///通用泛型转换,目标为DateTime,有效值840 ///841 [TestMethod]842 public void TestTo_DateTime() {843 Assert.AreEqual( new DateTime( 2000, 1, 1 ), Conv.To
( "2000-1-1" ) );844 }845 846 ///
847 ///通用泛型转换,目标为可空DateTime,无效值848 ///849 [TestMethod]850 public void TestTo_DateTimeOrNull_Invalid() {851 Assert.IsNull( Conv.To
( "1A" ) );852 }853 854 ///
855 ///通用泛型转换,目标为可空DateTime,有效值856 ///857 [TestMethod]858 public void TestTo_DateTimeOrNull() {859 Assert.AreEqual( new DateTime( 2000, 1, 1 ), Conv.To
( "2000-1-1" ) );860 }861 862 #endregion863 864 #endregion865 }866 }
ConvTest

  Conv类代码如下。

1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4   5 namespace Util {  6     ///   7     /// 类型转换  8     ///   9     public static class Conv { 10  11         #region 数值转换 12  13         ///  14         /// 转换为整型 15         ///  16         /// 数据 17         public static int ToInt( object data ) { 18             if ( data == null ) 19                 return 0; 20             int result; 21             var success = int.TryParse( data.ToString(), out result ); 22             if ( success == true ) 23                 return result; 24             try { 25                 return Convert.ToInt32( ToDouble( data, 0 ) ); 26             } 27             catch ( Exception ) { 28                 return 0; 29             } 30         } 31  32         ///  33         /// 转换为可空整型 34         ///  35         /// 数据 36         public static int? ToIntOrNull( object data ) { 37             if ( data == null ) 38                 return null; 39             int result; 40             bool isValid = int.TryParse( data.ToString(), out result ); 41             if ( isValid ) 42                 return result; 43             return null; 44         } 45  46         ///  47         /// 转换为双精度浮点数 48         ///  49         /// 数据 50         public static double ToDouble( object data ) { 51             if ( data == null ) 52                 return 0; 53             double result; 54             return double.TryParse( data.ToString(), out result ) ? result : 0; 55         } 56  57         ///  58         /// 转换为双精度浮点数,并按指定的小数位4舍5入 59         ///  60         /// 数据 61         /// 小数位数 62         public static double ToDouble( object data, int digits ) { 63             return Math.Round( ToDouble( data ), digits ); 64         } 65  66         ///  67         /// 转换为可空双精度浮点数 68         ///  69         /// 数据 70         public static double? ToDoubleOrNull( object data ) { 71             if ( data == null ) 72                 return null; 73             double result; 74             bool isValid = double.TryParse( data.ToString(), out result ); 75             if ( isValid ) 76                 return result; 77             return null; 78         } 79  80         ///  81         /// 转换为高精度浮点数 82         ///  83         /// 数据 84         public static decimal ToDecimal( object data ) { 85             if ( data == null ) 86                 return 0; 87             decimal result; 88             return decimal.TryParse( data.ToString(), out result ) ? result : 0; 89         } 90  91         ///  92         /// 转换为高精度浮点数,并按指定的小数位4舍5入 93         ///  94         /// 数据 95         /// 小数位数 96         public static decimal ToDecimal( object data, int digits ) { 97             return Math.Round( ToDecimal( data ), digits ); 98         } 99 100         /// 101         /// 转换为可空高精度浮点数102         /// 103         /// 数据104         public static decimal? ToDecimalOrNull( object data ) {105             if ( data == null )106                 return null;107             decimal result;108             bool isValid = decimal.TryParse( data.ToString(), out result );109             if ( isValid )110                 return result;111             return null;112         }113 114         /// 115         /// 转换为可空高精度浮点数,并按指定的小数位4舍5入116         /// 117         /// 数据118         /// 小数位数119         public static decimal? ToDecimalOrNull( object data, int digits ) {120             var result = ToDecimalOrNull( data );121             if ( result == null )122                 return null;123             return Math.Round( result.Value, digits );124         }125 126         #endregion127 128         #region Guid转换129 130         /// 131         /// 转换为Guid132         /// 133         /// 数据134         public static Guid ToGuid( object data ) {135             if ( data == null )136                 return Guid.Empty;137             Guid result;138             return Guid.TryParse( data.ToString(), out result ) ? result : Guid.Empty;139         }140 141         /// 142         /// 转换为可空Guid143         /// 144         /// 数据145         public static Guid? ToGuidOrNull( object data ) {146             if ( data == null )147                 return null;148             Guid result;149             bool isValid = Guid.TryParse( data.ToString(), out result );150             if ( isValid )151                 return result;152             return null;153         }154 155         /// 156         /// 转换为Guid集合157         /// 158         /// guid集合字符串,范例:83B0233C-A24F-49FD-8083-1337209EBC9A,EAB523C6-2FE7-47BE-89D5-C6D440C3033A159         public static List
ToGuidList( string guid ) {160 var listGuid = new List
();161 if ( string.IsNullOrWhiteSpace( guid ) )162 return listGuid;163 var arrayGuid = guid.Split( ',' );164 listGuid.AddRange( from each in arrayGuid where !string.IsNullOrWhiteSpace( each ) select new Guid( each ) );165 return listGuid;166 }167 168 #endregion169 170 #region 日期转换171 172 ///
173 /// 转换为日期174 /// 175 ///
数据176 public static DateTime ToDate( object data ) {177 if ( data == null )178 return DateTime.MinValue;179 DateTime result;180 return DateTime.TryParse( data.ToString(), out result ) ? result : DateTime.MinValue;181 }182 183 ///
184 /// 转换为可空日期185 /// 186 ///
数据187 public static DateTime? ToDateOrNull( object data ) {188 if ( data == null )189 return null;190 DateTime result;191 bool isValid = DateTime.TryParse( data.ToString(), out result );192 if ( isValid )193 return result;194 return null;195 }196 197 #endregion198 199 #region 布尔转换200 201 ///
202 /// 转换为布尔值203 /// 204 ///
数据205 public static bool ToBool( object data ) {206 if ( data == null )207 return false;208 bool? value = GetBool( data );209 if ( value != null )210 return value.Value;211 bool result;212 return bool.TryParse( data.ToString(), out result ) && result;213 }214 215 ///
216 /// 获取布尔值217 /// 218 private static bool? GetBool( object data ) {219 switch ( data.ToString().Trim().ToLower() ) {220 case "0":221 return false;222 case "1":223 return true;224 case "是":225 return true;226 case "否":227 return false;228 case "yes":229 return true;230 case "no":231 return false;232 default:233 return null;234 }235 }236 237 ///
238 /// 转换为可空布尔值239 /// 240 ///
数据241 public static bool? ToBoolOrNull( object data ) {242 if ( data == null )243 return null;244 bool? value = GetBool( data );245 if ( value != null )246 return value.Value;247 bool result;248 bool isValid = bool.TryParse( data.ToString(), out result );249 if ( isValid )250 return result;251 return null;252 }253 254 #endregion255 256 #region 字符串转换257 258 ///
259 /// 转换为字符串260 /// 261 ///
数据262 public static string ToString( object data ) {263 return data == null ? string.Empty : data.ToString().Trim();264 }265 266 #endregion267 268 #region 通用转换269 270 ///
271 /// 泛型转换272 /// 273 ///
目标类型
274 ///
数据275 public static T To
( object data ) {276 if ( data == null || string.IsNullOrWhiteSpace( data.ToString() ) )277 return default( T );278 Type type = Nullable.GetUnderlyingType( typeof( T ) ) ?? typeof( T );279 try {280 if ( type.Name.ToLower() == "guid" )281 return (T)(object)new Guid( data.ToString() );282 if ( data is IConvertible )283 return (T)Convert.ChangeType( data, type );284 return (T)data;285 }286 catch {287 return default( T );288 }289 }290 291 #endregion292 }293 }
Conv

  Conv公共操作类的用法,在单元测试中已经说得很清楚了,这也是单元测试的一个用途,即作为API说明文档。

  单元测试最强大的地方,可能是能够帮助你回归测试,如果你发现我的代码有BUG,请通知我一声,我只需要在单元测试中增加一个测试来捕获这个BUG,就可以永久修复它,并且由于采用TDD方式可以获得很高的测试覆盖率,所以我花上几秒钟运行一下全部测试,就可以知道这次修改有没有影响其它代码。这也是你创建自己的应用程序框架所必须要做的,它可以给你提供信心。

  可以看到,我在单元测试中进行了很多边界测试,比如参数为null或空字符串等。但不可能穷举所有可能出错的情况,因为可能想不到,另外时间有限,也不可能做到。当在项目上发现BUG后,再通过添加单元测试的方式修复BUG就可以了。由于你的项目代码调用的是应用程序框架API,所以你只需要在框架内修复一次,项目代码完全不动。

  像数据类型转换这样简单的操作,你发现写单元测试非常容易,因为它有明确的返回值,但如果没有返回值呢,甚至有外部依赖呢,那就没有这么简单了,需要很多技巧,所以你多看几本TDD和单元测试方面的著作有很多好处。

  另外,再补充一下,Conv这个类里面有几个法宝。一个是ToGuidList这个方法,当你需要把字符串转换为List<Guid>的时候就用它。还有一个泛型转换的方法To<T>,很多时候可以用它进行泛型转换。

  最后,我把所有方法参数类型都改成了object,主要是想使用起来方便一点,而不是只支持字符串参数,这可能导致装箱和拆箱,从而造成一些性能损失,不过我的大多数项目在性能方面还没有这么高的要求,所以这个损失对我来讲无关痛痒。

  还有些数据类型转换,我没有放进来,主要是我平时很少用到,当我用到时再增加。

  .Net应用程序框架交流QQ群: 386092459,欢迎有兴趣的朋友加入讨论。

  谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/xiadao521/

  下载地址: http://files.cnblogs.com/xiadao521/Util.2014.11.12.1.rar

你可能感兴趣的文章
IPsec ISAKMP(转)
查看>>
jquery js解析函数、函数直接调用
查看>>
对于eclipse building workspaces 慢的问题,解决方法
查看>>
ORACLE-行转列
查看>>
Java线程池关闭1-shutdown和isTerminated<转>
查看>>
【论文:麦克风阵列增强】An Algorithm For Linearly Constrained Adaptive Array Processing
查看>>
JPA相关注解
查看>>
HTML导航 - 点击更改背景
查看>>
leetcode 链表 Partition List
查看>>
织梦在服务器上面安装的时候一直提示data文件没有权限,可我已经写了权限,还是提示...
查看>>
自己动手做聊天机器人 一-涉及知识【转】
查看>>
Win2008R2配置WebDeploy发布网站
查看>>
vuex
查看>>
python os 模块
查看>>
卸载完百度影音以后天气助手还在,而且总是自己主动打开ie浏览器,解决方式...
查看>>
GO语言的进阶之路-协程和Channel
查看>>
Rust 1.7.0 处理命令行參数
查看>>
Oschina 安卓client源代码学习之中的一个
查看>>
halcon连续采集图像
查看>>
GitHub分支项目不支持搜索问题解决:Sorry, forked repositories are not currently searchable....
查看>>