a,泛型数据类型的构成基础
我们先来看看泛型单元中的前四个数据定义,他们是泛型构成的基础件:TArray(TObject),TEnumerator<T>(TObject),TEnumerable<T>(TObject),TListHelper(TObject)
TArray = class
private
class procedure QuickSort<T>(var Values: array of T; const Comparer: IComparer<T>;
L, R: Integer); static;
class procedure CheckArrays(Source, Destination: Pointer; SourceIndex, SourceLength, DestIndex, DestLength, Count: NativeInt); static;
public
class procedure Sort<T>(var Values: array of T); overload; static;
class procedure Sort<T>(var Values: array of T; const Comparer: IComparer<T>); overload; static;
class procedure Sort<T>(var Values: array of T;
const Comparer: IComparer<T>; Index, Count: Integer); overload; static;
class function BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer; const Comparer: IComparer<T>;
Index, Count: Integer): Boolean; overload; static;
class function BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer; const Comparer: IComparer<T>): Boolean; overload; static;
class function BinarySearch<T>(const Values: array of T; const Item: T;
out FoundIndex: Integer): Boolean; overload; static; static;
class procedure Copy<T>(const Source: array of T; var Destination: array of T; SourceIndex, DestIndex, Count: NativeInt); overload; static;
class procedure Copy<T>(const Source: array of T; var Destination: array of T; Count: NativeInt); overload; static;
end;
这是额外为TArray定义的一段代码,本人看得不是特别懂,感觉这个主要的功能是为System中的TArray<T>定义作一个扩展。
注意,TArray<T>的定义是出现在System单元中:TArray<T> = array of T;
这个TArray扩展为后续的泛型定义,提供了一个本体。接下来,我们看看两个抽象类:TEnumerator<T>,TEnumerable<T>.
TEnumerator<T> = class abstract
protected
function DoGetCurrent: T; virtual; abstract;
function DoMoveNext: Boolean; virtual; abstract;
public
property Current: T read DoGetCurrent;
function MoveNext: Boolean;
end;
TEnumerable<T> = class abstract
private
{$HINTS OFF}
function ToArrayImpl(Count: Integer): TArray<T>; // used by descendants
{$HINTS ON}
protected
function DoGetEnumerator: TEnumerator<T>; virtual; abstract;
public
destructor Destroy; override;
function GetEnumerator: TEnumerator<T>;
function ToArray: TArray<T>; virtual;
end;
这两个抽象类,TEnumerable是所有泛型的基类,定义出泛型的数据实体是TArray<T>模式,并且引用了另外一个抽象方法类TEnumerator ,使得泛型具备获取当前元素Current以及MoveNext导航功能。
这个设计很重要,我们可以看到Current和MoveNext在这里不再是数据结构的属性,而是作为元素基础功能出现的。
最后,我们再来看看一个附加的结构体:TListHelper = record ,它十分复杂,我没有太多时间去详细研究,暂时看到它是作为泛型的扩展属性使用的,所以就认为它是一个泛型的帮助信息扩展吧。
b,TList<T>
这个类型的篇幅还是比较长的,比TList要复杂多了,既融合了TList的基础定义,又加入了泛型的实现基础,下面我们一起看一看其定义的过程。
TList<T> = class(TEnumerable<T>)
private type
arrayofT = array of T; //定义了一个内部元数组类
var
FListHelper: TListHelper; // FListHelper must always be followed by FItems //暂且认为是帮助信息类,不做过多分析
FItems: arrayofT; // FItems must always be preceded by FListHelper //利用元数组类实现了一个元数据实体
FComparer: IComparer<T>; //为排序而诞生的比较方法指针
FOnNotify: TCollectionNotifyEvent<T>; //内部事件
function GetCapacity: Integer; inline; //得到整个泛型的内存空间
procedure SetCapacity(Value: Integer); overload; inline; //动态设置元素的Length
procedure SetCount(Value: Integer); inline; //动态设置元素个数
function GetItem(Index: Integer): T; inline; //根据序号获得指定元素
procedure SetItem(Index: Integer; const Value: T); inline;
procedure GrowCheck(ACount: Integer); inline; //Helper相关
procedure DoDelete(Index: Integer; Notification: TCollectionNotification); inline; //根据序号删除并销毁某元素
procedure InternalNotify(const Item; Action: TCollectionNotification);
function InternalCompare(const Left, Right): Integer;
property FCount: Integer read FListHelper.FCount write FListHelper.FCount;
protected
function ItemValue(const Item: T): NativeInt; //返回元素的值,NativeInt是内存中一种Int编码值。
function DoGetEnumerator: TEnumerator<T>; override; //重新构建元素的导航功能。
procedure Notify(const Item: T; Action: TCollectionNotification); virtual;
public
type
TDirection = System.Types.TDirection; //定义方向,用于List的定向操作
TEmptyFunc = reference to function (const L, R: T): Boolean; //为空时的匿名函数
TListCompareFunc = reference to function (const L, R: T): Integer; //为排序比较时的匿名函数
//再往下看基本就没什么新方法了,功能都是结合TList和TEnumerable的功能重组.
constructor Create; overload;
constructor Create(const AComparer: IComparer<T>); overload;
constructor Create(const Collection: TEnumerable<T>); overload;
destructor Destroy; override;
class procedure Error(const Msg: string; Data: NativeInt); overload; virtual;
{$IFNDEF NEXTGEN}
class procedure Error(Msg: PResStringRec; Data: NativeInt); overload;
{$ENDIF NEXTGEN}
function Add(const Value: T): Integer; inline;
procedure AddRange(const Values: array of T); overload;
procedure AddRange(const Collection: IEnumerable<T>); overload; inline;
procedure AddRange(const Collection: TEnumerable<T>); overload; inline;
procedure Insert(Index: Integer; const Value: T); inline;
procedure InsertRange(Index: Integer; const Values: array of T); overload;
procedure InsertRange(Index: Integer; const Collection: IEnumerable<T>); overload;
procedure InsertRange(Index: Integer; const Collection: TEnumerable<T>); overload;
procedure Pack; overload;
procedure Pack(const IsEmpty: TEmptyFunc); overload;
function Remove(const Value: T): Integer; inline;
function RemoveItem(const Value: T; Direction: TDirection): Integer; inline;
procedure Delete(Index: Integer); inline;
procedure DeleteRange(AIndex, ACount: Integer); inline;
function ExtractItem(const Value: T; Direction: TDirection): T; inline;
function Extract(const Value: T): T; inline;
procedure Exchange(Index1, Index2: Integer); inline;
procedure Move(CurIndex, NewIndex: Integer); inline;
function First: T; inline;
function Last: T; inline;
procedure Clear; inline;
function Expand: TList<T>; inline;
function Contains(const Value: T): Boolean; inline;
function IndexOf(const Value: T): Integer; inline;
function IndexOfItem(const Value: T; Direction: TDirection): Integer; inline;
function LastIndexOf(const Value: T): Integer; inline;
procedure Reverse; inline;
procedure Sort; overload;
procedure Sort(const AComparer: IComparer<T>); overload;
function BinarySearch(const Item: T; out Index: Integer): Boolean; overload;
function BinarySearch(const Item: T; out Index: Integer; const AComparer: IComparer<T>): Boolean; overload;
procedure TrimExcess; inline;
function ToArray: TArray<T>; override; final;
property Capacity: Integer read GetCapacity write SetCapacity;
property Count: Integer read FListHelper.FCount write SetCount;
property Items[Index: Integer]: T read GetItem write SetItem; default;
property List: arrayofT read FItems;
property OnNotify: TCollectionNotifyEvent<T> read FOnNotify write FOnNotify;
type //这里重新指定了元素导航的功能实现
TEnumerator = class(TEnumerator<T>)
private
FList: TList<T>;
FIndex: Integer;
function GetCurrent: T;
protected
function DoGetCurrent: T; override;
function DoMoveNext: Boolean; override;
public
constructor Create(const AList: TList<T>);
property Current: T read GetCurrent;
function MoveNext: Boolean;
end;
function GetEnumerator: TEnumerator; reintroduce; inline;
end;
该类应该是泛型中使用最为广泛的一个类,我们既可以用以后的类来组合使用,又可以重新定义其各项基础功能实现扩展。
直接使用的模式: DataSetList: TList<TDataSet>;
重新定义的模式:
type
TSpecList<T>=class(TList<T>)
....
end;
使用的时候直接将<T>实化:DataSetList: TSpecList<TDataSet>;
c,其他几种使用频率比较高的泛型:
TQueue<T> = class(TEnumerable<T>) //队列泛型,定义几乎跟TList<T> 一样,所以这里的方法说明省去。
TThreadList<T> = class //线程泛型,实体是TList<T>,针对其控制增加了锁定方法。
TStack<T> = class(TEnumerable<T>) //堆栈泛型,增加了Pop和Push方法,其他定义几乎跟TList<T>一致。
TPair<TKey,TValue> = record
Key: TKey;
Value: TValue;
constructor Create(const AKey: TKey; const AValue: TValue);
end;
TDictionary<TKey,TValue> = class(TEnumerable<TPair<TKey,TValue>>) //字典泛型,这个比较有用,数据是以Key和Value成对出现。主要是增加了Hash方法,各种元素操作也都以Key作为参数。
这些泛型都是基于数据结构的变化。
d,与对象相关的泛型扩展 TObjectList<T>,
TObjectList<T: class> = class(TList<T>)
private
FOwnsObjects: Boolean;
protected
procedure Notify(const Value: T; Action: TCollectionNotification); override;
public
constructor Create(AOwnsObjects: Boolean = True); overload;
constructor Create(const AComparer: IComparer<T>; AOwnsObjects: Boolean = True); overload;
constructor Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload;
destructor Destroy; override;
property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects; //主要就是增加了这个属性,让其元素耦合性降低
end;
TObjectQueue<T: class> = class(TQueue<T>)
TObjectStack<T: class> = class(TStack<T>)
TObjectDictionary<TKey,TValue> = class(TDictionary<TKey,TValue>)
以上这四种泛型都是在原有泛型上的轻微扩展,同列表的对象扩展一样。最主要的属性就是OwnsObjects,使得整个泛型数据集,可以拥有对象空间的独立管理能力。
3,小结
为什么我们要使用泛型?泛型数据的优势和劣势又各是什么呢?
其实Delphi引用泛型数据算比较落后的了,Java很早就有泛型概念,而FrameWork也是从2.0 开始就引入了泛型数据,而Delphi是从Delphi2009~Delphi2010才正式引入泛型。
泛型的早期模式,其实就是各种列表,也就是本篇的第1点所阐述的内容,对比泛型和列表,其实泛型能实现的方式列表都可以实现,而列表的异构元素结构,泛型是不适合的。
那么泛型相对列表有什么优势呢?优势主要体现在两个方面:重用性,安全高效性。
a,重用性
这里举个例子说明,我们如果需要两个列表TStringxxxList,TIntxxxList,如果用列表继承的概念,那就必须要写两个定义:
type TStringList=class(TList)
...这可能会有count方法
end;
type TIntxxxList=class(TList)
...这可能会有count方法
end;
如果换作泛型,就只需要定义一次就好了,列表中通性的方法是固定的。
type TxxxList<T>=class(TList<T>)
...这里可能有count方法
end;
使用时,我们用TxxxList<string>,TxxxList<Int>就可以取代两种List。
b,安全高效性
虽然用列表也可以实现子类型的存取,但是在使用过程中就免不了要进行类型转换和判断(装箱和拆箱),即不安全,也会影响到系统效率。
例如:
AllDataSets : TComponentList; //用List进行一个数据集的存储。
AllDataSets := TComponentList.Create(False); //非耦合性列表
AllDataSets.Add(ADataSet); //存放一个数据集
到这一步似乎跟泛型都没什么差异,然而取的时候就比较麻烦了。
if AllDataSets.Items[ADataSetNo] is TDataSet then
funxxx(AllDataSets.Items[ADataSetNo] as TDataSet);
这不仅仅意味着要承受各种非规则数据的干扰,还必须进行强制类型转换,才能完成其初期设计的【数据集列表】这样的概念。反观泛型就要简单得多:
定义:AllDataSets : TObjectList<TDataSet>;
AllDataSets := TObjectList<TDataSet>.Create(False);
AllDataSets.Add(ADataSet);
我们在使用中,完全不担心类型问题,直接调用就好了,而且即便真的有类型匹配的错误,在编译期就可以将其呈现出来。