• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

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

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

快速导航:

一、概述

二、体验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>作对比,保存一组整形数据。使用控制台的方式进行程序编写。


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

运行结果:


图2

三、体验TObjectList<T>

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

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

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

1unitFelix;
2
3interface
4
5uses
6SysUtils;
7
8type
9TFelix=class
10private
11fId:Integer;
12public
13constructorCreate;virtual;
14destructorDestroy;override;
15propertyId:IntegerreadfIdwritefId;
16end;
17
18var
19gCount:Integer;
20
21implementation
22
23{TFelix}
24
25constructorTFelix.Create;
26begin
27fId:=gCount;
28Writeln('ConstructorFelix'+IntToStr(fId));
29Inc(gCount);
30end;
31
32destructorTFelix.Destroy;
33begin
34Writeln('DestructorFelix'+IntToStr(fId));
35
36inherited;
37end;
38
39end.
40

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->1unitFelix;
2
3interface
4
5uses
6SysUtils;
7
8type
9TFelix=class
10private
11fId:Integer;
12public
13constructorCreate;virtual;
14destructorDestroy;override;
15propertyId:IntegerreadfIdwritefId;
16end;
17
18var
19gCount:Integer;
20
21implementation
22
23{TFelix}
24
25constructorTFelix.Create;
26begin
27fId:=gCount;
28Writeln('ConstructorFelix'+IntToStr(fId));
29Inc(gCount);
30end;
31
32destructorTFelix.Destroy;
33begin
34Writeln('DestructorFelix'+IntToStr(fId));
35
36inherited;
37end;
38
39end.

控制台程序代码:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->1programTestTObjectList;
2
3{$APPTYPECONSOLE}
4
5uses
6SysUtils,
7Contnrs,
8Generics.Collections,
9Felixin'Felix.pas';
10
11var
12objList:TObjectList<TFelix>;
13oldObjList:TObjectList;
14n:Integer;
15felix:TFelix;
16pFelix:Pointer;
17begin
18//以下代码测试旧对象集合
19Writeln('TObjectListstart');
20
21oldObjList:=TObjectList.Create;//1*
22forn:=0to2do
23begin
24oldObjList.Add(TFelix.Create);
25end;
26
27forpFelixinoldObjListdo
28begin
29Writeln(TFelix(pFelix).Id);
30end;
31
32FreeAndNil(oldObjList);
33
34//以下代码测试泛型对象集合
35Writeln(#13+#10+'TObjectList<T>start');
36
37objList:=TObjectList<TFelix>.Create;//2*
38forn:=0to2do
39begin
40objList.Add(TFelix.Create);
41end;
42
43forfelixinobjListdo
44begin
45Writeln(felix.Id);
46end;
47
48FreeAndNil(objList);
49
50//----------------------------------------------------------
51Writeln('pressanykey');
52Readln;
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的类似,看了看代码,真是让人遐想连篇,此处不再介绍。

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap