查看: 6957|回复: 0
打印 上一主题 下一主题

.NET泛型技巧之类型参数之间的转换

[复制链接]
跳转到指定楼层
1#
发表于 2008-11-1 10:19:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
台州网址导航
首先我要介绍的技巧是如何提供类型参数之间的转换。我们知道,.NET泛型将每个类型参数理解为一个独立的类型。如果不通过约束指定,编译器不会对类型参数所代表的类型做任何假设。也就是说,如果在某个上下文中有两个不同的类型参数U和V,编译器不会知道运行时他们代表的真实类型能否进行类型转换,因此会拒绝编译如下代码:

以下为引用的内容:
Public Function GenericCast(Of U, V)(ByVal obj As U) As V
 Return CType(obj, V)
End Function



除非我们加以约束U是V的子类。这显然是为了类型安全做出的考虑,因为.NET这种跨程序集的泛型无法在编译时做出足够的检查来确保类型安全。但是限制了这种操作,就妨碍了我们做事,很多代码因此写不出来。于是,我们可以利用.NET所有类型的基类Object来绕过这一限制:

Return DirectCast(DirectCast(obj, Object), V)

VB的DirectCast运算符在泛型的类型参数上作用与C#的括号运算符相同。也就是说,这段代码用C#写起来是这样:

return (V)(object)obj;
这样,即使不约束U和V之间的关系,这段代码也能编译了。但是他的功能却不能令我们满意。这样写出的类型转换实际上还是仅当U是V本身或其子类的时候才能转换成功。而其他一切情况都会转换失败。不管U和V的运行时类型之间是否定义有其他类型转换规则。这显然不合我们意愿,我们希望int与double之间的转换等语言内置的类型转换都能够自动进行,否则就和约束没什么两样了。对VB用户来说有一个极为简单的解决方案——把第二次DirectCast变成CType:

以下为引用的内容:
Public Function GenericCast(Of U, V)(ByVal obj As U) As V
 Return CType(DirectCast(obj, Object), V)
End Function



现在,GenericCast泛型方法就能执行int与double等内置规则的转换了。很神奇?因为CType运算符在编译时自动调用了VB运行库的转换函数,该函数在运行期间对泛型类型参数的真实类型做了检查。而且这个过程的性能完全可以接受。

现在VB的用户已经轻松享受这一功能了。但是C#的事情还没完,因为C#没有如此智能的类型转换运算符,因此就需要手工实现VB运行库所代办的那些任务。其实就是利用了一下IConvertible:

以下为引用的内容:
static V GenericCast<U, V>(U obj)
{
 IConvertible convertibleObj = obj as IConvertible;
 if (convertibleObj != null)
 {
  Type t = typeof(V);

  switch (Type.GetTypeCode(t))
  {
   case TypeCode.Boolean:
    return (V)(object)convertibleObj.ToBoolean(null);
   case TypeCode.Byte:
    return (V)(object)convertibleObj.ToByte(null);
   case TypeCode.Char:
    return (V)(object)convertibleObj.ToChar(null);

   //.........
   default:
    //None of them, use the following default way..
    break;
  }
 }
 return (V)(object)obj;
}


不过这个方法看起来不但很丑、很麻烦,功能上还达不到VB版。所以建议您用到这种类型参数之间的转换,就用VB封装这一功能,然后做成dll供C#调用吧。

经过研究发现Convert.ChangeType方法已经封装了IConvertible判断的那些代码,因此C#版可采用这种写法:

以下为引用的内容:
static V GenericCast<U, V>(U obj)
{
 return (V)Convert.ChangeType(obj, typeof(V));
}


不过它仍然没有VB版的CType功能丰富。此外我还发现了VB运行库的ChangeType还有支持用户自定义类型转换运算符的功能。所以终极版本如下:

以下为引用的内容:
Public Function GenericCast(Of U, V)(ByVal obj As U) As V
Try
 Return CType(DirectCast(obj, Object), V)
 Catch ex As InvalidCastException Return DirectCast( _
  CompilerServices.Conversions.ChangeType(obj, GetType(V)), V)
 End Try
End Function
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 转播转播 分享分享 分享淘帖
台州维博网络(www.tzweb.com)专门运用PHP+MYSQL/ASP.NET+MSSQL技术开发网站门户平台系统等。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

网站推广
关于我们
  • 台州朗动科技(Tzweb.com)拥有多年开发网站平台系统门户手机客户端等业务的成功经验。主要从事:政企网站,系统平台,微信公众号,各类小程序,手机APP客户端,浙里办微应用,浙政钉微应用、主机域名、虚拟空间、后期维护等服务,满足不同企业公司的需求,是台州地区领先的网络技术服务商!

Hi,扫描关注我

Copyright © 2005-2026 站长论坛 All rights reserved

Powered by 站长论坛 with TZWEB Update Techonolgy Support

快速回复 返回顶部 返回列表