适用版本:.NET4.0以上
在最近参与的一个项目中,需要同时读取PMI标注和制图标注的信息,以此推广,其实在项目实践中,获取同一类相似对象的某些信息的需求,是很常见的。这种情况我们可以写几套代码,来对每种类型的对象进行处理,也可以使用今天介绍的多态以及动态类型来进行统一处理。
多态是面向对象的三大特征之一,指为不同数据类型的对象提供统一的接口,或使用一个单一的符号来表示多个不同的类型。
动态类型(dynamic)是在C#4中引入的一个新类型 ,我们知道C#本身是一个强类型的编程语言,强类型的好处是编写程序时,编译器可以实时提示我们关于类型的错误,缺点是灵活性相比Python这种动态类型的语言有所不足。但在引入了动态类型以后,一定程度上弥补了这部分缺点。但是需要注意的是,动态类型本质上来说仍然是一种静态类型,只是声明为 dynamic 的对象会跳过编译时静态类型检查。但是,如果代码无效,则在运行时仍然报错。
下面就以获取角度尺寸的样式为例,先介绍一下多态的应用。
先说明一下,由于对象类型的全名过长,为了便于查看,下面提到的API类型,如无特殊说明,均来自NXOpen.Annotations名称空间,下面的说明均省略这个名称空间。
如下图1所示,角度尺寸在PMI标注中的类型为:
PmiMinorAngularDimension
图1 PmiMinorAngularDimension类型的继承关系
如下图2所示,创建PMI角度尺寸的Builder为:
PmiMinorAngularDimensionBuilder
创建这个Builder的方法为:
DimensionCollection.CreatePmiMinorAngularDimensionBuilder
图2 PmiMinorAngularDimensionBuilder的继承关系
如下图3所示,角度尺寸在制图中的类型为:
MinorAngularDimension
图3 MinorAngularDimension的继承关系
如下图4所示,创建制图角度尺寸的Builder为:
MinorAngularDimensionBuilder
创建这个Builder的方法为:
DimensionCollection.CreateMinorAngularDimensionBuilder
图4 MinorAngularDimensionBuilder的继承关系
查看API手册可以知道,要想获取角度尺寸的标注样式,需要先创建一个对应的尺寸的Builder,再通过
BaseAngularDimensionBuilder.Style这个属性来获取。
同时通过上面的继承关系,我们可以看到,PMI角度尺寸和制图角度尺寸,都继承自BaseAngularDimension,而创建二者的Builder,又都继承自BaseAngularDimensionBuilder。
到这里,我们设想一下,如果这里有一个通用的方法:
无论我们输入PMI角度尺寸还是制图角度尺寸,由于这两个类都继承自BaseAngularDimension,所以都是合法的。
那么使用这一个方法,就能同时获取两种角度尺寸类型的Builder了,再从这个Builder中获取Style属性,我们的问题就解决了。但是很可惜,BaseAngularDimension这个类是一个抽象类,API中并没有提供创建这个类的实例的方法。
但是,我们可以自己写一个,代码如下所示。
这里使用了C#中的扩展方法,这样在代码中,我们就能像使用原生方法一样,直接调用我们自己的方法了。
获取样式的方法就很简单了:
全部调用代码如下:
动态类型的优势在于灵活性,它的应用场景和多态有相似性,也有一些区别。
如果我们将上面的场景稍微改变一下,两个类型的Builder的基类BaseAngularDimensionBuilder中,并没有Style这个属性,而是将Style属性分别封装到了各自的Builder类中,那么上面的代码在编译时就会报错,提示BaseAngularDimensionBuilder中找不到Style这个属性。这时候我们就可以利用动态类型来处理这个问题,代码如下:
我们先将角度尺寸的Builder声明为dynamic类型,这样在编译时,就不会去检查这个对象的类型,而是在运行时去执行检查。需要注意的是,声明为dynamic类型的对象在编写代码时,VisualStudio中的自动代码提示功能是关闭的(这也是理所当然的,编译器根本不知道这个对象应该是什么类型),所以我们在编码时需要注意拼写正确,否则运行时会报错。另外,声明为dynamic类型的对象具有传染性,也就是说,如果我们将上图中的result习惯性地声明为var,那么这个对象的类型也将被编译器推断为dynamic,如下图所示:
所以我们在编码时,应该尽量将dynamic类型的范围控制在最小范围内,什么时候不需要动态类型了,就应该根据实际的代码,立刻显式地指定对象的类型,这样就能够获得VisualStudio的自动代码提示的支持,从而更大可能地减少拼写错误造成程序运行时错误的问题。
多态技术在面向对象领域的应用是非常广泛的,但是使用的时候应当注意是否会存在拆箱和装箱,从而可能引起性能问题。
动态类型的优点在于灵活,但是由于动态类型在编译时不进行检查,可能会把一些拼写问题带到运行时中。
其实在.NET中,还可以使用反射技术来解决上述的问题,读者如果有兴趣,可以自己查阅相关资料,今天的分享就先到这里了。