[导入]泛型技巧系列:简单类型选择器
2006-02-24 11:14
309 查看
注意:本系列未经许可,不得转载。
在泛型编程当中,我们对类型的关注大大提高了。有时需要这样的功能:“当类型是A的时候执行这段代码;当类型是B的时候执行另一段代码”。就是说,需要针对类型进行分支选择。当前,我们有三种机制可以实现这种分支选择:1、根据编译期声明类型选择的函数重载机制。2、根据运行时类型的虚函数-重写机制。3、If语句+类型判断。我们使用面向对象和泛型中的某些机制都是为了消除If语句带来的影响,所以这个时候使用If语句可能令人不太兴奋。但是有时候If语句是唯一的实现方式,我们可以将If封装到基础逻辑中以消除它的不利影响。
本来在泛型世界中,我们应该有特化或偏特化手段,用以实现类型方面的匹配式选择。但是.NET泛型没有提供这一机制。那么我们就只能利用运行期类型比较加以模拟。但问题就出来了:运行期类型与声明类型可以是不同的,比如一个对象可以声明成Object类型,但运行时可以是String类型。这种情况下,使用TypeOf运算符(C#的is运算符)的行为将和编译期选择的行为不同。如何让运行期也能识别编译期声明类型呢?上次讲到抽象工厂的实现时,我们提到了一个工具——TypeToken,我们还可以利用它!不过这次我要改个名字:TypeMate,因为我发现.NET Framework中也有一个东东叫TypeToken,起名字真难啊。。这就是TypeMate的定义:
Public NotInheritable Class TypeMate(Of T)
Private Sub New()
End Sub
Public Shared ReadOnly Value As TypeMate(Of T) = New TypeMate(Of T)
End Class 这个和上次的TypeToken几乎一样,唯一不同就是把属性换成了静态只读字段。因为TypeToken的运行时作用很小,所以我们不能让他在运行时带来太多负担。TypeMate(Of T)与T一一对应,但不管T之间有什么继承关系,各个TypeMate(Of T)之间都没有任何关系,更进一步的是,TypeMate(Of T)的实例将会把T的编译期类型带到运行期,这个正是我们需要的。
接下来我们定义TypeSwitch,作为应用TypeMate的第一个例子,他实现了我们开始的想法,能够根据声明类型进行分派选择。
Public MustInherit Class TypeSwitch(Of T1, T2)
Public MustOverride Sub Fire(ByVal m As TypeMate(Of T1))
Public MustOverride Sub Fire(ByVal m As TypeMate(Of T2))
Public Sub Fire(Of T)(ByVal m As TypeMate(Of T))
Dim typeless = m
If TypeOf typeless Is TypeMate(Of T1) Then
Fire(TypeMate(Of T1).Value)
ElseIf TypeOf typeless Is TypeMate(Of T2) Then
Fire(TypeMate(Of T2).Value)
Else
Throw New ArgumentException("No matched type")
End If
End Sub
End Class 注意,为什么除了两个基本的Fire虚方法,还需要带有第三个类型参数的Fire方法呢?这全怪.NET泛型的局限性,编译器在编译的时候无法推测类型参数实际表示的类型,只能把这件事推迟到运行时来做。
现在我们用一个例子看看这种方法与普通的函数重载有什么不同。先定义一个字符串和整数的选择器:
Class Test
Inherits TypeSwitch(Of Integer, String)
Public Overloads Overrides Sub Fire(ByVal m As TypeMate(Of Integer))
Console.WriteLine("Interger!")
End Sub
Public Overloads Overrides Sub Fire(ByVal m As TypeMate(Of String))
Console.WriteLine("String!")
End Sub
End Class 下面我们编写一个利用该选择器进行类型选择的代码例子:
Module Module1
Sub Main()
Dim o As Object = "abc"
Dim s As String = "abc"
SwitchByDeclarationType(o)
SwitchByDeclarationType(s)
End Sub
Sub SwitchByDeclarationType(Of T)(ByVal arg As T)
Dim switch As TypeSwitch(Of Integer, String) = New Test
switch.Fire(TypeMate(Of T).Value)
End Sub
End Module 注意泛型算法SwitchByDeclarationType,他利用TypeSwitch功能实现了针对类型参数T(而不是一个具体类型)的判断与分派功能。虽然判断的过程在运行时,效果却是根据参数的声明类型,而不是运行时类型来选择的。例子中两个变量运行时都是字符串,但是object那一次调用的时候会失败。
文章来源:http://blog.joycode.com/ninputer/archive/2006/02/16/71535.aspx
在泛型编程当中,我们对类型的关注大大提高了。有时需要这样的功能:“当类型是A的时候执行这段代码;当类型是B的时候执行另一段代码”。就是说,需要针对类型进行分支选择。当前,我们有三种机制可以实现这种分支选择:1、根据编译期声明类型选择的函数重载机制。2、根据运行时类型的虚函数-重写机制。3、If语句+类型判断。我们使用面向对象和泛型中的某些机制都是为了消除If语句带来的影响,所以这个时候使用If语句可能令人不太兴奋。但是有时候If语句是唯一的实现方式,我们可以将If封装到基础逻辑中以消除它的不利影响。
本来在泛型世界中,我们应该有特化或偏特化手段,用以实现类型方面的匹配式选择。但是.NET泛型没有提供这一机制。那么我们就只能利用运行期类型比较加以模拟。但问题就出来了:运行期类型与声明类型可以是不同的,比如一个对象可以声明成Object类型,但运行时可以是String类型。这种情况下,使用TypeOf运算符(C#的is运算符)的行为将和编译期选择的行为不同。如何让运行期也能识别编译期声明类型呢?上次讲到抽象工厂的实现时,我们提到了一个工具——TypeToken,我们还可以利用它!不过这次我要改个名字:TypeMate,因为我发现.NET Framework中也有一个东东叫TypeToken,起名字真难啊。。这就是TypeMate的定义:
Public NotInheritable Class TypeMate(Of T)
Private Sub New()
End Sub
Public Shared ReadOnly Value As TypeMate(Of T) = New TypeMate(Of T)
End Class 这个和上次的TypeToken几乎一样,唯一不同就是把属性换成了静态只读字段。因为TypeToken的运行时作用很小,所以我们不能让他在运行时带来太多负担。TypeMate(Of T)与T一一对应,但不管T之间有什么继承关系,各个TypeMate(Of T)之间都没有任何关系,更进一步的是,TypeMate(Of T)的实例将会把T的编译期类型带到运行期,这个正是我们需要的。
接下来我们定义TypeSwitch,作为应用TypeMate的第一个例子,他实现了我们开始的想法,能够根据声明类型进行分派选择。
Public MustInherit Class TypeSwitch(Of T1, T2)
Public MustOverride Sub Fire(ByVal m As TypeMate(Of T1))
Public MustOverride Sub Fire(ByVal m As TypeMate(Of T2))
Public Sub Fire(Of T)(ByVal m As TypeMate(Of T))
Dim typeless = m
If TypeOf typeless Is TypeMate(Of T1) Then
Fire(TypeMate(Of T1).Value)
ElseIf TypeOf typeless Is TypeMate(Of T2) Then
Fire(TypeMate(Of T2).Value)
Else
Throw New ArgumentException("No matched type")
End If
End Sub
End Class 注意,为什么除了两个基本的Fire虚方法,还需要带有第三个类型参数的Fire方法呢?这全怪.NET泛型的局限性,编译器在编译的时候无法推测类型参数实际表示的类型,只能把这件事推迟到运行时来做。
现在我们用一个例子看看这种方法与普通的函数重载有什么不同。先定义一个字符串和整数的选择器:
Class Test
Inherits TypeSwitch(Of Integer, String)
Public Overloads Overrides Sub Fire(ByVal m As TypeMate(Of Integer))
Console.WriteLine("Interger!")
End Sub
Public Overloads Overrides Sub Fire(ByVal m As TypeMate(Of String))
Console.WriteLine("String!")
End Sub
End Class 下面我们编写一个利用该选择器进行类型选择的代码例子:
Module Module1
Sub Main()
Dim o As Object = "abc"
Dim s As String = "abc"
SwitchByDeclarationType(o)
SwitchByDeclarationType(s)
End Sub
Sub SwitchByDeclarationType(Of T)(ByVal arg As T)
Dim switch As TypeSwitch(Of Integer, String) = New Test
switch.Fire(TypeMate(Of T).Value)
End Sub
End Module 注意泛型算法SwitchByDeclarationType,他利用TypeSwitch功能实现了针对类型参数T(而不是一个具体类型)的判断与分派功能。虽然判断的过程在运行时,效果却是根据参数的声明类型,而不是运行时类型来选择的。例子中两个变量运行时都是字符串,但是object那一次调用的时候会失败。
文章来源:http://blog.joycode.com/ninputer/archive/2006/02/16/71535.aspx
相关文章推荐
- 泛型技巧系列:简单类型选择器
- 泛型技巧系列:类型字典和Type Traits
- 泛型技巧系列:如何提供类型参数之间的转换
- 泛型技巧系列:如何提供类型参数之间的转换
- 泛型技巧系列:如何提供类型参数之间的转换
- 泛型技巧系列:类型字典和Type Traits
- 泛型技巧系列:如何提供类型参数之间的转换
- 泛型技巧系列:避免基类及接口约束
- Java 泛型-简单泛型存储多种类型对象
- 再谈怎样以最简单的方法将泛型为String类型的集合或String类型的数组转化为逗号间隔字符串形式
- JXL(针对Excel操作)系列之二:最简单的导入操作(main)
- 统一沟通-技巧-1-导入-证书-信任链-如此简单!
- excel导入sql数据,数字类型字段变科学计数的简单解决办法
- sqoop针对联合主键的表导入hbase的简单控制技巧
- 【JavaSE系列-基础篇6】——泛型类型
- 简单分析.net泛型中的类型参数
- 【收藏】泛型技巧系列---by装配脑袋
- JavaSE_8系列博客——Java语言的特性(六)--泛型(3)--泛型和类型通配符
- [导入]Community Server系列之七:快速找到需要修改的文件[技巧] [转]
- [导入]数据库设计技巧系列(一)——设计数据库之前