(原创)Delphi2009初体验 - 语言篇 - 体验泛型(一)

快速导航:

一、概述

二、体验TList<T>

三、体验TObjectList<T>

四、TList<T>和TObjectList<T>的区别

五、后记

一、概述

等了几百年,Delphi终于原生的支持泛型了。以前使用Delphi,泛型是不被支持的,但是可以用一些第三方库来实现间接的泛型容器支持。如HouSisong大虾编制的DGL泛型库,只需要创建几个简单的“头”文件,就可以拥有指定类型的容器集合类。DGL泛型库非常类似于STL泛型库,很容易上手,如果大家想知道具体使用方法,我另外开文章说明。

 

Delphi2009提供了几个好用的泛型容器,如TList<T>TQueue<T>TStack<T>TDictionary<TKey, TValue>,还有针对于对象使用的TObjectList<T>等几个类。此外,还提供了TArray数组辅助静态类,封装了数组(array of T)的几个常用操作,如排序等。

 

但是在智能感知的时候,TList<T>等泛型集合提示好像有些BUG

1

 

为什么是“[]”,而不是“()”?

 

下面针对TList和TObjectList及两者的区别对Delphi2009的泛型功能进行初步体验。

二、体验TList<T>

在此,我将使用以前版本的指针集合类TList与TList<T>作对比,保存一组整形数据。使用控制台的方式进行程序编写。

 

 1program TestTList;
 2
 3{$APPTYPE CONSOLE}
 4
 5uses
 6    SysUtils,
 7    Classes,
 8    Generics.Collections; // 泛型集合命名空间,太优美了!
 9
10var
11    intList: TList<Integer>;
12    oldList: TList;
13    n, elem: Integer;
14    pTmp: Pointer;
15begin
16    // 以下代码测试旧的集合对象
17    oldList := TList.Create;
18    oldList.Add(Pointer(1));
19    oldList.Add(Pointer(2));
20    oldList.Add(Pointer(3));
21
22    Writeln('TList start');
23
24    for n := 0 to oldList.Count - 1 do
25    begin
26        Writeln(Integer(oldList[n]));
27    end;
28
29    for pTmp in oldList do
30    begin
31        Writeln(Integer(pTmp));
32    end;
33
34    FreeAndNil(oldList);
35
36    // 以下代码测试整形泛型集合对象
37    intList := TList<Integer>.Create;
38    intList.Add(1);
39    intList.Add(2);
40    intList.Add(3);
41
42    Writeln( #13 + #10 + 'TList<T> start');
43
44    for n := 0 to intList.Count - 1 do
45    begin
46        Writeln(intList[n]);
47    end;
48
49    for elem in intList do
50    begin
51        Writeln(elem);
52    end;
53
54    FreeAndNil(intList);
55
56    // ----------------------------------------------------------
57    Writeln('press any key');
58    Readln;
59end.

 

运行结果:

 

图2

三、体验TObjectList<T>

刚开始看到TObjectList的时候我有点不解,既然是泛型,那么T就不区分值类型和引用类型,为什么还会多出来一个TObjectList<T>呢?在阅读了Generic.Collections的源码和经过试验后,我终于明白了原因,待我来慢慢分析。

同样,我将使用Contnrs命名空间下的TObjectList和TObjectList<T>做对比,使用控制台程序进行程序的编写。

首先创建一个类,该类在创建时,对象将打印“创建 ” + 对象的索引号,销毁时打印“销毁 ” + 对象的索引号:

 

 1 unit Felix;
 2 
 3 interface
 4 
 5 uses
 6     SysUtils;
 7 
 8 type
 9     TFelix = class
10     private
11         fId: Integer;
12     public
13         constructor Create; virtual;
14         destructor Destroy; override;
15         property Id: Integer read fId write fId;
16     end;
17 
18 var
19     gCount: Integer;
20 
21 implementation
22 
23 { TFelix }
24 
25 constructor TFelix.Create;
26 begin
27     fId := gCount;
28     Writeln('Constructor Felix ' + IntToStr(fId));
29     Inc(gCount);
30 end;
31 
32 destructor TFelix.Destroy;
33 begin
34     Writeln('Destructor Felix ' + IntToStr(fId));
35 
36     inherited;
37 end;
38 
39 end.

 

 控制台程序代码:

 

 1program TestTObjectList;
 2
 3{$APPTYPE CONSOLE}
 4
 5uses
 6    SysUtils,
 7    Contnrs,
 8    Generics.Collections,
 9    Felix in 'Felix.pas';
10
11var
12    objList: TObjectList<TFelix>;
13    oldObjList: TObjectList;
14    n: Integer;
15    felix: TFelix;
16    pFelix: Pointer;
17begin
18    // 以下代码测试旧对象集合
19    Writeln('TObjectList start');
20
21    oldObjList := TObjectList.Create;  // 1*
22    for n := 0 to 2 do
23    begin
24        oldObjList.Add(TFelix.Create);
25    end;
26
27    for pFelix in oldObjList do
28    begin
29        Writeln(TFelix(pFelix).Id);
30    end;
31
32    FreeAndNil(oldObjList);
33
34    // 以下代码测试泛型对象集合
35    Writeln(#13 + #10 + 'TObjectList<T> start');
36
37    objList := TObjectList<TFelix>.Create;  // 2*
38    for n := 0 to 2 do
39    begin
40        objList.Add(TFelix.Create);
41    end;
42
43    for felix in objList do
44    begin
45        Writeln(felix.Id);
46    end;
47
48    FreeAndNil(objList);
49
50    // ----------------------------------------------------------
51    Writeln('press any key');
52    Readln;
53end.

 

 

图3

 

如果我们将代码中的第1*处修改成:

oldObjList := TObjectList.Create(False);

将产生如下结果:

 

 

图4

 

相对于TObjectList<T>,没有Create(AOwnsObjects: Boolean)方式的重载,我们如何才能让TObjectList<T>“不拥有”对象,当TObjectList<T>中的元素重新赋值、TObjectList<T>集合对象销毁的时候,怎样能保证里面的旧元素不进行销毁操作呢?答案是:不能。

四:TList<T>和TObjectList<T>的区别

如果将上面代码的objList对象声明时改成TList<TFelix>类型,并将第2*处代码改成objList := TList<TFelix>.Create;结果就和使用TObjectList(图4)的效果一样了,当调用方法SetItem或者集合被销毁后,旧元素或者内部的元素不会被销毁。

原因在于,TObjectList<T>从TList<T>继承而来,只重写了Notify方法,此方法在集合内元素改变(指针变换、删除、添加)等操作时调用。

请阅读Generics.Collections.pas文件第1236行,TObjectList<T>重写了Notify方法后,先调用了超类的Notify方法,然后判断操作如果为cnRemoved则将元素.Free,所以元素在此处被析构。

五:后记

使用TObjectList<T>会将对象自动销毁,使用TList<T>不会将对象自动销毁。
受Symbian编程的影响,我习惯于对象自己创建、对象自己销毁,特别是在使用对象集合类,有时候一个对象可能在这个集合内,同时又在另外一个集合内。如果TObjectList<T>把对象销毁了,在另外一个集合内使用对象会造成不可预料的后果,所以建议大家不要使用TObjectList<T>。

其他几个泛型类TDictionary<>等,方法和代码都和.net的类似,看了看代码,真是让人遐想连篇,此处不再介绍。

 

标签: Delphi2009
posted @ 2008-08-22 18:11 杨芹勍 阅读(8496) 评论(36) 编辑 收藏

 回复 引用 查看   
#1楼2008-08-22 13:39 | net1234      
给个下载地址,谢谢
 回复 引用 查看   
#2楼2008-08-22 14:14 | 齐.net      
哇,最开始也是学DELPHI的啊,2009感觉很强
 回复 引用   
#3楼2008-08-22 14:18 | aaronlive[未注册用户]
朋友,你在哪里下载的Delphi 2009呢?
可否给个链接,我也下来体验一下啊

 回复 引用   
#4楼2008-08-22 14:18 | 欧阳西风[未注册用户]
易用好用就行,或许他们都很像,没有关系...遐想也无妨...呵...
 回复 引用 查看   
#5楼2008-08-22 14:28 | Justin      
2009都出来啦,很怀念Delphi
 回复 引用 查看   
#6楼2008-08-22 14:30 | 陛下      
delphi, 不容易啊。
 回复 引用   
#7楼2008-08-22 14:32 | 郁闷中[未注册用户]
问一下,用Delphi2009开发的程序会不会象net一样要带个那么大的运行库啊,
还有就是支持面向对象开发吗?
个人觉得vs2003以后的版本不合适开发通用型的应用程序,因为要操作系统没有带运行库啊,很麻烦

 回复 引用 查看   
#8楼[楼主]2008-08-22 14:36 | Felix Yeou      
 回复 引用 查看   
#9楼[楼主]2008-08-22 14:36 | Felix Yeou      
@Justin

是呀,很怀念BORLAND,曾今传奇的公司

 回复 引用   
#10楼2008-08-22 14:39 | 东方剑[未注册用户]
@郁闷中
delphi开发是windows原生程序,当然不需要像.net哪样的2,3百M运行环境库支持.
object delphi早就是面向对象的了.
通用程序,多媒体,等大多数还用vc++,delphi较好了,不过以后很难讲,我觉得如果以数据库为侧重应用,还是.net快捷方便,如果开发类似QQ等东西还是delphi等好些,布署也方便.

 回复 引用 查看   
#11楼[楼主]2008-08-22 14:42 | Felix Yeou      
@郁闷中

这个问题问的好,Delphi做出来的程序,一直都不要运行库支持,做出来的软件就一个EXE文件(除非您自己想做其他DLL配合)。Delphi做出来的程序都是绿色软件,体积小,效率高。

ps:Windows优化大师就是用Delphi做的。WinRAR是用Delphi的兄弟软件BCB做的。


Delphi当然支持面向对象,在Delphi的前身OOP Pascal都支持的很非常好。很多高校就用OOP Pascal作为学生面向对象的入门语言。

 回复 引用   
#12楼2008-08-22 14:56 | elsee[未注册用户]
好東西,從2005年開始本來想學,沒有想到看到這麼多唉聲,我還以為,差不多要掛了,現在看到2009出來,唉
 回复 引用 查看   
#13楼[楼主]2008-08-22 15:22 | Felix Yeou      
@elsee

呵呵,不要再“唉”了,我现在也不用Delphi做软件,但是我一直关注他,真心希望有一天它能够强大到能够运用在多人协作的项目上。

 回复 引用 查看   
#14楼2008-08-22 16:16 | 装配脑袋      
这个泛型支持T.create吗?,支持特化,偏特化之类的吗?支持继承T吗?支持按类型参数重载吗?支持T的RTTI吗?支持class field对每个C<T>中T的不同而不同吗?应该调查一下有多强大,以便进行泛型编程的研究
 回复 引用 查看   
#15楼[楼主]2008-08-22 16:18 | Felix Yeou      
@装配脑袋
我会在随后的文章里,详细解答您的疑问

 回复 引用 查看   
#16楼2008-08-22 16:20 | 装配脑袋      
@Felix Yeou

我都等不及了,有没有Delphi 2009 Express之类的免费版本啊……

 回复 引用 查看   
#17楼[楼主]2008-08-22 16:22 | Felix Yeou      
@装配脑袋
有的。这个网站提供了链接:http://www.jycrop.com/

 回复 引用 查看   
#18楼2008-08-22 16:39 | Windie Chai(笑煞天)      
俺是从Delphi6开始学习Delphi的,自从Delphi支持.net之后就不用它了。
 回复 引用 查看   
#19楼[楼主]2008-08-22 16:43 | Felix Yeou      
@Windie Chai(笑煞天)

恩,我也不用Delphi.net,告诉你一个好消息,Delphi2009不提供Delphi for .net,Delphi2009是原生的win32 Delphi。

Delphi for .net将以另外一个产品的形式发布。

 回复 引用 查看   
#20楼2008-08-22 17:11 | 菩提树下的杨过      
勾起了我曾经的美好回忆!
 回复 引用 查看   
#21楼2008-08-22 17:31 | 装配脑袋      
那个文件我下载不了啊,公司不让装任何下载软件、插件。能否传一个到Windows Live SkyDrive上去呢。。。
 回复 引用   
#22楼2008-08-22 17:44 | A.Z![未注册用户]
pascal已经没有多少人用了。
 回复 引用 查看   
#23楼[楼主]2008-08-22 18:13 | yeou      
@装配脑袋
好的,我等会发给您。

 回复 引用   
#24楼2008-08-22 20:44 | 傻妞-cynthia[未注册用户]
牛人
看不懂

 回复 引用 查看   
#25楼2008-08-23 00:27 | 私家侦探      
@东方剑
...如果以数据库为侧重应用,还是.net快捷方便
-----------------------------------------
是快捷方便,但是
看看天空下载里面的行业软件有几个是vs2001以后开发的?
行业软件和企业息息相关,基本上是基于数据库的,因为运行库的原因造成很多人放弃用vs开发通用数据库程序.不过如果是企业内部自己开发或定制,那么vs就大有作为.反正vs不适合做通用的东西

 回复 引用 查看   
#26楼2008-08-23 01:10 | 怪怪      
@装配脑袋
嘿嘿, 等着你的试验报告了~

 回复 引用 查看   
#27楼2008-08-23 09:24 | 木野狐(Neil Chen)      
我也讨厌装下载工具.
 回复 引用 查看   
#28楼2008-08-23 11:02 | BruceZhou      
bucuobucuo
 回复 引用 查看   
#29楼2008-08-24 12:25 | 5207      
D7之后的版本我们都没采用过。这次的版本不知道能不能用起来。。

接下来易博龙可能会在数据库级开发出招了。。希望能打破是JAVA和。NET的格局。

DELPHI必须走一条真正属于程序员的路。

 回复 引用   
#30楼2008-08-24 18:31 | 2222222222[未注册用户]
B/S开发还VS。
 回复 引用   
#31楼2008-08-29 22:08 | 金丝猴[未注册用户]
有中文版吗!?
 回复 引用   
#32楼2008-08-31 18:25 | sdf[未注册用户]
纳米盘下载,大概2个多小时(电信)
 回复 引用   
#33楼2008-12-15 21:24 | anypsky[未注册用户]
D2009出来后让用Passcal的兄弟们看到了希望,希望delphi继续创造神话
 回复 引用 查看   
#34楼2008-12-27 09:48 | Jaypei      
谢谢你的文章~
我在用的时候发现Delphi 2009的IDE好像对泛型语法识别不了,泛型成员老出红曲线提示"Undeclared identifier"。

 回复 引用 查看   
#35楼[楼主]2009-01-08 11:43 | 杨芹勍      
@Jaypei
最新版的IDE已经对泛型支持得很好了

 回复 引用 查看   
#36楼2010-06-17 16:08 | 封涨停      
不喜欢Delphi,尤其是pascal的语法,特别笨重。还是类c语言优美。