您的位置:首页 > 编程语言 > Delphi

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

2008-08-22 18:11 369 查看
快速导航:

一、概述

二、体验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:

program TestTList;

2

3{$APPTYPE CONSOLE}

4

5uses

6 SysUtils,

7 Classes,

8 Generics.Collections; // 泛型集合命名空间,太优美了!

9

var

intList: TList<Integer>;

oldList: TList;

n, elem: Integer;

pTmp: Pointer;

begin

// 以下代码测试旧的集合对象

oldList := TList.Create;

oldList.Add(Pointer(1));

oldList.Add(Pointer(2));

oldList.Add(Pointer(3));

Writeln('TList start');

for n := 0 to oldList.Count - 1 do

begin

Writeln(Integer(oldList
));

end;

for pTmp in oldList do

begin

Writeln(Integer(pTmp));

end;

FreeAndNil(oldList);

// 以下代码测试整形泛型集合对象

intList := TList<Integer>.Create;

intList.Add(1);

intList.Add(2);

intList.Add(3);

Writeln( #13 + #10 + 'TList<T> start');

for n := 0 to intList.Count - 1 do

begin

Writeln(intList
);

end;

for elem in intList do

begin

Writeln(elem);

end;

FreeAndNil(intList);

// ----------------------------------------------------------

Writeln('press any key Readln;

end.

运行结果:

program TestTObjectList;

2

3{$APPTYPE CONSOLE}

4

5uses

6 SysUtils,

7 Contnrs,

8 Generics.Collections,

9 Felix in 'Felix.pas';

var

objList: TObjectList<TFelix>;

oldObjList: TObjectList;

n: Integer;

felix: TFelix;

pFelix: Pointer;

begin

// 以下代码测试旧对象集合

Writeln('TObjectList start');

oldObjList := TObjectList.Create; // 1*

for n := 0 to 2 do

begin

oldObjList.Add(TFelix.Create);

end;

for pFelix in oldObjList do

begin

Writeln(TFelix(pFelix).Id);

end;

FreeAndNil(oldObjList);

// 以下代码测试泛型对象集合

Writeln(#13 + #10 + 'TObjectList<T> start');

objList := TObjectList<TFelix>.Create; // 2*

for n := 0 to 2 do

begin

objList.Add(TFelix.Create);

end;

for felix in objList do

begin

Writeln(felix.Id);

end;

FreeAndNil(objList);

// ----------------------------------------------------------

Writeln('press any key Readln;

end.



图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的类似,看了看代码,真是让人遐想连篇,此处不再介绍。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: