Vb.Net中有一个CType函数,可以实现常规基础数据类型和引用数据类型的类型转换。为了让C#中也能拥有一个类似功能的函数,我们平台还提供了另外一个基于Object的扩展方法CType,可以实现多种数据类型之间的转换。
先来了解一下VB.Net中的CType有哪些使用场景。
'基础数据类型转换 Dim x As String = CType(5,String) Dim y As Integer = CType("5",Integer) Dim b As Boolean = CType("True",Boolean) 'Enum枚举类型转换 Dim a As FormShowType = CType(1,FormShowType) Dim v As Integer = CType(FormShowType.Model,Integer) Private Sub ButtonClick(sender As Object, e As EventArgs) '有继承或实现关系的引用类型之间的转换 Dim btn As Button = CType(sender,Button) Dim frm As SmForm=CType(btn.Tag,SmForm) Dim ctrl As IControl=CType(btn,IControl) End Sub |
如果我们仔细观察会发现,上面的这些使用场景其实是跟我们“隐式转换”差不多一致的,也就是说在VB.net中大多数时候,我们是可以不用CType进行类型转换的。一旦我们使用了,得注意此函数如果转换类型不成功是会抛出异常的。我们在使用时就不得不注意处理异常信息。
那么Object的扩展方法CType在C#中又是如何使用的呢?
C# |
int intNum = 2; // 已知类型的转换可以正常进行 Proj.MsgDebug.Add(intNum.CType<string>()); string strNum = "2.34"; Proj.MsgDebug.Add(strNum.CType<decimal>().CType<string>()); object obj = "2.674"; // Object类型的转换在C#中可以正常使用 Proj.MsgDebug.Add(obj.CType<decimal>().ToString()); string strDate="2022-07-06 13:25:36"; Proj.MsgDebug.Add(strDate.CType<DateTime>().ToString()); //取当前表当前行第一列的值 string strCell=Proj.CurrentGrid.CurrentRowData[0].CType<string>(""); Proj.MsgDebug.Add(strCell); //转换引用类型 SmGrid tbl=Proj.CurrentGrid.CType<SmGrid>(); Proj.MsgDebug.Add(tbl.Name); //转换接口 IDataRuleGrid dataGrid=tbl.CType<IDataRuleGrid>(); Proj.MsgDebug.Add(dataGrid.Form.Name); |
因为是基于Object类型扩展而来的方法,所以可以非常方便地在任何类型上直接进行转换,链式代码编写方式非常方便。此CType扩展方法,如果转换失败的话,会返回指定类型默认值。
数据类型 | 返回默认值 |
字符串 | "" |
数值 | 0 |
日期 | DateTime.MinValue |
逻辑 | FALSE |
但是为了让使用上更方便,我们还给这个扩展方法添加了一个重载,如果转换失败,可以自己指定一个初始值。
C# |
//先获得当前表当前行 RowData dr=Proj.CurrentGrid.CurrentRowData; //将当前行中Enum列中的值转换为FormShowType类型,如果转换失败(或为空值时)可以返回指定的默认值 FormShowType showType= dr["Enum"].CType<FormShowType>(FormShowType.Standard); Proj.MsgDebug.Add(showType.ToString()); |
我们总结一下CType扩展方法有以下几个优点:
1、基于Object扩展,在任何类型上都可以方便地进行类型转换。链式代码编写非常方便。
2、类型转换失败也不会报错,仅返回将要转换类型的默认值。
3、我们还可以自己指定在转换失败后返回什么默认值。
4、既可以转换基础类型,也可以转换有继承或实现关系的引用类型。基本全能。
用回VB.net
既然此扩展函数如此好用,那我们能不能用回Vb.Net呢?我们先来试试吧。
在测试的过程中我们发现上面的代码在编译时报错了:未找到类型”String"”的公共成员”CType"。
好好的代码为什么就出错了呢?我也找了好久的答案,最终在stackoverflow网站中找到的结论:
翻译一下就是,因为VB.Net的后期绑定特性,而无法支持Object的扩展方法。因为“我们可以防止扩展方法完全破坏现有的后期绑定代码的唯一方法是防止它们被用于任何类型化为Object的对象”。这是Vb.Net在设计时就已经决定好的。
既然这样以后我们想要用CType这个扩展方法时,只能在一些确定的基础类型上使用。另外,如果真的非常想用此扩展方法的话,也可以利用静态类直接引用的方式使用。
Vb.Net |
Dim intNum As Integer=2'已知类型的转换可以正常进行 Proj.MsgDebug.Add(intNum.CType(Of String)) '返回结果:2 Dim strNum As String="2.34" Proj.MsgDebug.Add(strNum.CType(Of Decimal).ToString()) '返回结果:2.34 Dim obj As Object="2.674" 'Object类型的转换会报错,这个是VB.Net的限制,针对Object的扩展无法对Object类型起效果 '如果想使用扩展方法的话,可以考虑以静态方法方式调用 Proj.MsgDebug.Add(ObjectExtension.CType(Of Decimal)(obj)) '返回结果:2.674 obj=1 Proj.MsgDebug.Add(ObjectExtension.CType(Of AggregateEnum)(obj)) '返回结果:AggregateEnum.Clear '模拟转换失败的场景 obj=Nothing Proj.MsgDebug.Add(ObjectExtension.CType(Of AggregateEnum)(obj,AggregateEnum.Max)) '返回结果:AggregateEnum.Max |
如果是对RowData数据行返回的数据进行转换的话,可以考虑:
dr("列名称").ToString().CType(Of Decimal)