Santé

为明天干杯!
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

From Resizing Arrays To Generic

Posted on 2005-04-05 13:34  smalldust  阅读(636)  评论(0编辑  收藏  举报

前些日子,在Ninputer的Blog拜读了其大作《VB.Net是怎样做到的》,列出了10多点VB.net当中有,而C#没有的功能或特性。对于喜欢C#的人,可能会觉得很郁闷吧。

那么到底能否因此说VB比C#功能强大呢?我觉得并非如此。这10多点VB.net的特性中,有的的确是.Net框架中有,但是C#没有提供的机能,有的则只是比C#更高一层的封装。对于后者换句话来说,就如同C和汇编。C用printf语句显示字符,汇编为了显示字符则必须读字串、调用中断……需要一大堆代码。但是并不能因此就说C比汇编强,只能说汇编更接近底层,适合系统内核级的程序;C把底层封装起来,更适合编写高层应用。同样C#和VB.net多多少少也有这种区别;只不过是.Net平台让这种区别变得很小而以了。不仅如此,VB.Net当中有些语句只是为了兼容而已,未必见得有多么先进和独到。这里就用数组做为例子做一个说明。

许多C#的程序员都很郁闷,C#中数组是固定大小的(而ArrayList之类的可变数组又失去了类型上的便利)。如果数组能够有Add, Remove该多好,哪怕只有Resize也好啊——有了Resize,其他的也就可以写出来了。

我们不妨稍稍考虑一下,如何为数组增加Resize方法?首先数组在内存中的存储结构是一段连续的地址空间,这就注定了其长处是快速的索引及搜索,短处则是增删无法像链表那么灵活。但是正因为数组是连续的,所以也就方便了其复制(当然是浅拷贝)。因此通过复制,理论上讲完全可以写出Resize代码的:

int [] Resize(int [] a, int newLength)
{
    
//我们为了复制a显然需要一个临时变量b,并让b的长度为你需要的长度……
    int []b = new int[newLength];
    Array.Copy(a, b, newLength);
    
return b;
    
//
}


且慢,我们遇到一个问题。现在我们的Resize方法可以用来复制int数组,可是如果要把这段Resize代码做成通用代码(不仅对int数组可以使用,对任意类型数组都可以使用),b的类型以及返回值应该定义为什么?

(给初学者:不要想重载,世界上有无穷无尽的类型,所以你需要重载无穷无尽个J

首先想到的可能是使用多态。通过转换为基类以及装箱,——也就是把Resize写成object [] Resize(object [] a, int newLength),的确我们可以成功的接受各种类型的数组作为参数。而且,Console.WriteLine之类的方法也的确是采用的这种方法。

但是,这种方法根本无法做到——这个函数要返回值,可是它如果返回一个object[],而且是能被转换为某种类型A的object[],那么这个object[]的实际类型必须是A。我们既然不知道A,就无法作出实际类型为A的object[]。

那么,我们就只能在编译或运行期间推断我们的Resize代码被用在了哪种数组上。对于Resize(a),我们就使相应的Resize代码中的b以及返回值为a的类型。VB.net当中ReDim使用的正是这种方法。

那么这种方法都有什么缺点呢?

可以说,这种方法其实就是泛型。但是VB.net当中的Redim其实远比泛型差得远。试一下这个VB.net程序就知道了:

Sub Main()
        
Dim a(10as Interger
        ResizeAll(a, 
20)
End Sub


Sub ResizeAll(ByRef arr As Array, ByVal newLength As Integer)
        
ReDim arr(newLength)
End Sub


代码的结果是不能运行。虽然我没有深入编译器查看究竟是什么原因使ReDim无法对Array类型使用,但是显然的,ReDim是无法探知Array的真实类型。所以说,VB.Net当中的ReDim,只是为了向前兼容而残留的不完善的语句,既不符合面向对象的要求(对于这样的方法应当封装给对象),又不能完善的解决类型的问题,注定会被其他方法替代。

最终的解决方案,相信大家都已经知道了,那就是泛型。C#2.0当中(当然不仅仅是C#)提供了完善的泛型的支持,相信一定会把大家从不断进行object到某个类型的cast中解救出来。

注:本人也是对.Net/C#一知半解,甚至于对VB.Net几乎不解。所以有什么错误请大家务必指出以免误人子弟。另,不知道本文是否通俗易懂,如果有个别不懂得词请查Google,语言不通的话请予以指出^_^