淺談如何使用Delphi 2009的泛型容器類別(續)
luyued 发布于 2011-03-19 21:36 浏览 N 次
使用TDictionary容器類別
Delphi 2009中的容器類別TDictionary對於許多日常開發的工作中非常的有用,例如我們經常需要在應用程式中使用一個鍵值來搜尋相關的資料,在這種應用中TDictionary容器類別便非常適合。
TDictionary容器類別的第一個即代表鍵值,第二個代表這個鍵值相關的數值,由於TDictionary是泛型容器類別,所以它的鍵值和數值都可以是任何的型態。現在就讓我們看看如何使用TDictionary,我們仍然繼續使用前面討論的範例做為說明。
假設現在我們希望統計一下glProduct中Delphi和BCB的產品個數是多少,那麼我們可以使用TDictionary來儲存<產品名稱, 個數>這樣的資訊,因此我們需要建立一個TDictionary的物件來使用。
TDictionary提供了許多不同的原型的建構函式,其中最簡單的建構函式擁有如下的原型宣告:
constructor Create(ACapacity: Integer = 0); overload;
這個建構函式接受一個內定大小的參數ACapacity,這個參數是指TDictionary物件在建立之後先在其中預先建立多少個元素。為什麼需要這樣?這是因為我們在建立了TDictionary物件之後一定會在其中加入元素(不然為什麼需要建立TDictionary物件呢?),由於TDictionary比較複雜,因此如果我們預先在其中先建立一些元素空間以便稍後使用,這樣的執行效率會比較好,否則稍後當我們在TDictionary物件中加入元素時TDictionary物件就需要動態增加它的的元素空間大小,這樣會影響執行效率。
下面的程式碼就是實作統計glProduct中Delphi和BCB的產品個數是多少的程式碼,首先我們先建立TDictionary物件aDic並且預先在其中建立可儲存5個元素大小的空間,接著我們藉由TEnumerator物件一一從glProduct中最出產品名稱,然後呼叫TDictionary的ContainsKey方法來查詢這個產品名稱鍵值是否已經存在aDic之中,如果產品名稱鍵值已經存在,那麼就呼叫TDictionary的AddOrSetValue方法增加這個產品名稱的個數,否則就在aDic中加入這個<產品名稱, 1>這對鍵值和數值,最後呼叫DisplayProductCount來顯示統計的數值。
procedure TForm17.btn統計產品總數Click(Sender: TObject);
var
aDic: TDictionary;
aEnum : TEnumerator;
begin
aDic := TDictionary.Create(5);
try
aEnum := glProduct.GetEnumerator;
while (aEnum.MoveNext) do
begin
if (aDic.ContainsKey(aEnum.Current.GetCategory)) then
aDic.AddOrSetValue(aEnum.Current.GetCategory, aDic.Items[aEnum.Current.GetCategory] + 1)
else
aDic.Add(aEnum.Current.GetCategory, 1);
end;
DisplayProductCount(aDic);
finally
aDic.Free;
end;
end;
DisplayProductCount接受型態為TDictionary的參數,然後也是藉由TDictionary的Enumerator來一一取出其中的元素來處理,不過TDictionary提供了三種Enumerator,分別是TPairEnumerator,TKeyEnumerator和TValueEnumerator。從這三個Enumerator的名稱我們便可以知道,TPairEnumerator可以取出這對<鍵值, 數值>的元素,而TKeyEnumerator則可取出<鍵值>元素,最後的TValueEnumerator則是取出<數值>元素。
由於TPairEnumerator,TKeyEnumerator和TValueEnumerator都是宣告在TDictionary之中的內嵌類別,因此在宣告這三個Enumerator類別的變數時需要在之前加上TDictionary。例如下面的程式碼中aEnum是宣告為TpairEnumerator,但是在這之前我們需要加入TDictionary的宣告並且正確的帶入資料型態,因此aEnum的正確型態宣告是TDictionary.TPairEnumerator。
TPairEnumerator的使用方法和TEnumerator是一樣的,但是TPairEnumerator的Current特性值的型態是:
TPair
而TPair只是鍵值和數值成對的記錄型態而已
TPair = record
Key: TKey;
Value: TValue;
end;
TPair的目的是方便讓開發人員一次可以藉由Current取出對應的鍵值和數值。
procedure TForm17.DisplayProductCount(aDic: TDictionary);
var
aEnum : TDictionary.TPairEnumerator;
begin
Self.lb產品資料.Items.Clear;
aEnum := aDic.GetEnumerator;
while (aEnum.MoveNext) do
begin
Self.lb產品資料.Items.Add(aEnum.Current.Key + ' : ' + IntToStr(aEnum.Current.Value));
end;
end;
TCollectionNotifyEvent
elphi 2009的泛型容器類別也提供了通知事件,允許開發人員連結此事件以便撰寫程式碼來處理元素在容器類別中異動的情形。在Generics.Collections程式單元中定義了如下的通知事件:
TCollectionNotification = (cnAdded, cnRemoved, cnExtracted);
TCollectionNotifyEvent = procedure(Sender: TObject; const Item: T;
Action: TCollectionNotification) of object;
開發人員可以藉由實作型態為TCollectionNotifyEvent的函式,再連結到容器類別物件即可在元素被加入,移除或是取出容器類別被容
器類別物件呼叫知會。
例如我們可以使用下面的程式碼連結glProduct容器類別物件:
procedure TForm17.btn連結通知事件Click(Sender: TObject);
begin
glProduct.OnNotify := ProductNotifier;
end;
而ProductNotifier就是實作TCollectionNotifyEvent原型的方法,在這裡ProductNotifier會在容器類別物件中的元素異動時顯示簡單的訊息:
procedure TForm17.ProductNotifier(Sender: TObject; const Item: TProduct;
Action: TCollectionNotification);
begin
case Action of
cnAdded:
Self.lb通知事件.Items.Add('加入 : ' + Item.GetName);
cnRemoved:
Self.lb通知事件.Items.Add('移除 : ' + Item.GetName);
cnExtracted:
Self.lb通知事件.Items.Add('取出 : ' + Item.GetName);
end;
end;
深入討論匿名方法
前面討論了匿名方法,匿名方法除了可以和泛型一起使用之外,也可以使用在非泛型的應用程式之中。由於匿名方法是在程式碼中定義函式本身,因此匿名方法也需要一個定義的範圍和呼叫模式,否則匿名方法本身要儲存在那裡呢?因此現在讓我們稍微深入討論一下匿名方法的實作機制,讓各位對於匿名方法有更基礎的瞭解。
Delphi 2009是使用介面的方式來實作匿名方法,這樣做有許多的好處,主要的原因是使用介面可以進行型態檢查以及以及在Win32下缺少資源回收機制的環境中可以比較方便進行資源管理,此外Delphi(Object Pascal)又是強型程式語言,因此在編譯時期提供較為嚴格的檢查也和Delphi程式語言相當的契合。
讓我們看一個範例也許會讓讀者更為瞭解匿名方法的實作方式。假設我們有下面的程式碼:
type
TFuncOfInt = reference to function(x: Integer): Integer;
function MakeAdder(addendum: Integer): TFuncOfInt;
begin
Result := function(x: Integer)
begin
Result := addendum + x;
end;
end;
procedure Use;
var
f: TFuncOfInt;
begin
f := MakeAdder(20);
Writeln(f(22)); // prints '42'
end;
begin
Use;
end.
在MakeAdder中定義了一個匿名方法,而且又把這個匿名方法當成MakeAdder的回傳參數,而這個匿名方法的原型則是由TFuncOfInt定義的。OK,那麼Delphi 2009是如何實作上面使用匿名方法的程式碼呢? 首先Delphi 2009的編譯器會把TfuncOfInt重新定義為如介面,並且在其中定義一個Invoke方法,類似如下:
type
TFuncOfInt = interface
function Invoke(x: Integer): Integer;
end;
接著在MakeAdder中實際定義了匿名方法,因此在MakeAdder方法中必須定義此匿名方法的程式區塊,因為匿名方法可以擁有它自己的參數,變數,堆疊資源等。因此下面是MakeAdder可能實作的程式碼:
function MakeAdder(addendum: Integer): TFuncOfInt;
type
IClosure1 = interface
function Invoke(x: Integer): Integer;
end;
TMakeAdderFrame = class(TInterfacedObject, IClosure1)
addendum: Integer;
function IClosure1.Invoke = Closure1;
function Closure1(x: Integer): Integer;
end;
function TMakeAdderFrame.Closure1(x: Integer);
begin
Result := Self.addendum + x;
end;
首先MakeAdder會宣告一個IClosure介面,其中定義Invoke方法,接著MakeAdder會宣告一個內嵌類別TMakeAdderFrame,這個類別將實作Closure介面並且把匿名方法拉出去成為內嵌類別的方法,接著把匿名方法的父方法的參數宣告為物件變數,如此一來就可以解決巢狀參數/變數的問題。
最後在MakeAdder方法的實作程式碼中,就建立內嵌類別物件,最後MakeAdder方法要回傳匿名方法時,這裡是稍微複雜的地方。
var
frameInstance: TMakeAdderFrame;
begin
frameInstance := TMakeAdderFrame.Create;
frameInstance.addendum := addendum;
Result := reinterpret_cast(interface_cast(frameInstance));
end;
首先MakeAdder必須把TMakeAdderFrame物件轉變型態為IClosure介面,這可以使用interface_cast來調整vTable的內容指標,接著使用reinterpret_cast強迫轉變型態為TFuncOfInt,也就是MakeAdder回傳的型態,如此一來就大功告成了。
procedure Use;
var
f: TFuncOfInt;
begin
f := MakeAdder(20);
Writeln(f.Invoke(22));
end;
begin
Use;
end.
OK,我這篇淺談如何使用Delphi 2009泛型容器類別的文章也就到此結束了,希望對於想使用Delphi 2009泛型實體類別的讀者有一些基本的幫助。
Have Fun!
Delphi 2009中的容器類別TDictionary
TDictionary
假設現在我們希望統計一下glProduct中Delphi和BCB的產品個數是多少,那麼我們可以使用TDictionary
TDictionary
constructor Create(ACapacity: Integer = 0); overload;
這個建構函式接受一個內定大小的參數ACapacity,這個參數是指TDictionary
下面的程式碼就是實作統計glProduct中Delphi和BCB的產品個數是多少的程式碼,首先我們先建立TDictionary
procedure TForm17.btn統計產品總數Click(Sender: TObject);
var
aDic: TDictionary
aEnum : TEnumerator
begin
aDic := TDictionary
try
aEnum := glProduct.GetEnumerator;
while (aEnum.MoveNext) do
begin
if (aDic.ContainsKey(aEnum.Current.GetCategory)) then
aDic.AddOrSetValue(aEnum.Current.GetCategory, aDic.Items[aEnum.Current.GetCategory] + 1)
else
aDic.Add(aEnum.Current.GetCategory, 1);
end;
DisplayProductCount(aDic);
finally
aDic.Free;
end;
end;
DisplayProductCount接受型態為TDictionary
由於TPairEnumerator,TKeyEnumerator和TValueEnumerator都是宣告在TDictionary
TPairEnumerator的使用方法和TEnumerator是一樣的,但是TPairEnumerator的Current特性值的型態是:
TPair
而TPair只是鍵值和數值成對的記錄型態而已
TPair
Key: TKey;
Value: TValue;
end;
TPair的目的是方便讓開發人員一次可以藉由Current取出對應的鍵值和數值。
procedure TForm17.DisplayProductCount(aDic: TDictionary
var
aEnum : TDictionary
begin
Self.lb產品資料.Items.Clear;
aEnum := aDic.GetEnumerator;
while (aEnum.MoveNext) do
begin
Self.lb產品資料.Items.Add(aEnum.Current.Key + ' : ' + IntToStr(aEnum.Current.Value));
end;
end;
TCollectionNotifyEvent
elphi 2009的泛型容器類別也提供了通知事件,允許開發人員連結此事件以便撰寫程式碼來處理元素在容器類別中異動的情形。在Generics.Collections程式單元中定義了如下的通知事件:
TCollectionNotification = (cnAdded, cnRemoved, cnExtracted);
TCollectionNotifyEvent
Action: TCollectionNotification) of object;
開發人員可以藉由實作型態為TCollectionNotifyEvent
器類別物件呼叫知會。
例如我們可以使用下面的程式碼連結glProduct容器類別物件:
procedure TForm17.btn連結通知事件Click(Sender: TObject);
begin
glProduct.OnNotify := ProductNotifier;
end;
而ProductNotifier就是實作TCollectionNotifyEvent
procedure TForm17.ProductNotifier(Sender: TObject; const Item: TProduct;
Action: TCollectionNotification);
begin
case Action of
cnAdded:
Self.lb通知事件.Items.Add('加入 : ' + Item.GetName);
cnRemoved:
Self.lb通知事件.Items.Add('移除 : ' + Item.GetName);
cnExtracted:
Self.lb通知事件.Items.Add('取出 : ' + Item.GetName);
end;
end;
深入討論匿名方法
前面討論了匿名方法,匿名方法除了可以和泛型一起使用之外,也可以使用在非泛型的應用程式之中。由於匿名方法是在程式碼中定義函式本身,因此匿名方法也需要一個定義的範圍和呼叫模式,否則匿名方法本身要儲存在那裡呢?因此現在讓我們稍微深入討論一下匿名方法的實作機制,讓各位對於匿名方法有更基礎的瞭解。
Delphi 2009是使用介面的方式來實作匿名方法,這樣做有許多的好處,主要的原因是使用介面可以進行型態檢查以及以及在Win32下缺少資源回收機制的環境中可以比較方便進行資源管理,此外Delphi(Object Pascal)又是強型程式語言,因此在編譯時期提供較為嚴格的檢查也和Delphi程式語言相當的契合。
讓我們看一個範例也許會讓讀者更為瞭解匿名方法的實作方式。假設我們有下面的程式碼:
type
TFuncOfInt = reference to function(x: Integer): Integer;
function MakeAdder(addendum: Integer): TFuncOfInt;
begin
Result := function(x: Integer)
begin
Result := addendum + x;
end;
end;
procedure Use;
var
f: TFuncOfInt;
begin
f := MakeAdder(20);
Writeln(f(22)); // prints '42'
end;
begin
Use;
end.
在MakeAdder中定義了一個匿名方法,而且又把這個匿名方法當成MakeAdder的回傳參數,而這個匿名方法的原型則是由TFuncOfInt定義的。OK,那麼Delphi 2009是如何實作上面使用匿名方法的程式碼呢? 首先Delphi 2009的編譯器會把TfuncOfInt重新定義為如介面,並且在其中定義一個Invoke方法,類似如下:
type
TFuncOfInt = interface
function Invoke(x: Integer): Integer;
end;
接著在MakeAdder中實際定義了匿名方法,因此在MakeAdder方法中必須定義此匿名方法的程式區塊,因為匿名方法可以擁有它自己的參數,變數,堆疊資源等。因此下面是MakeAdder可能實作的程式碼:
function MakeAdder(addendum: Integer): TFuncOfInt;
type
IClosure1 = interface
function Invoke(x: Integer): Integer;
end;
TMakeAdderFrame = class(TInterfacedObject, IClosure1)
addendum: Integer;
function IClosure1.Invoke = Closure1;
function Closure1(x: Integer): Integer;
end;
function TMakeAdderFrame.Closure1(x: Integer);
begin
Result := Self.addendum + x;
end;
首先MakeAdder會宣告一個IClosure介面,其中定義Invoke方法,接著MakeAdder會宣告一個內嵌類別TMakeAdderFrame,這個類別將實作Closure介面並且把匿名方法拉出去成為內嵌類別的方法,接著把匿名方法的父方法的參數宣告為物件變數,如此一來就可以解決巢狀參數/變數的問題。
最後在MakeAdder方法的實作程式碼中,就建立內嵌類別物件,最後MakeAdder方法要回傳匿名方法時,這裡是稍微複雜的地方。
var
frameInstance: TMakeAdderFrame;
begin
frameInstance := TMakeAdderFrame.Create;
frameInstance.addendum := addendum;
Result := reinterpret_cast
end;
首先MakeAdder必須把TMakeAdderFrame物件轉變型態為IClosure介面,這可以使用interface_cast來調整vTable的內容指標,接著使用reinterpret_cast強迫轉變型態為TFuncOfInt,也就是MakeAdder回傳的型態,如此一來就大功告成了。
procedure Use;
var
f: TFuncOfInt;
begin
f := MakeAdder(20);
Writeln(f.Invoke(22));
end;
begin
Use;
end.
OK,我這篇淺談如何使用Delphi 2009泛型容器類別的文章也就到此結束了,希望對於想使用Delphi 2009泛型實體類別的讀者有一些基本的幫助。
Have Fun!
相关资讯
- 07-01· 禁教唐诗算术能还幼儿快
- 07-01· 2011年06月17日
- 07-01· 唐诗宋词英译:李商隐 筹
- 07-01· 仿评《唐诗1000首》第186首
- 07-01· 没事干的时候背背唐诗吧
- 07-01· [转载]唐诗中“斜”字该读
- 07-01· 湖南醴陵瓷业转型升级
- 07-01· 奇瑞风云2两厢黑色|2010款
- 07-01· 摩根士丹利华鑫摩根士丹
- 07-01· 摩根士丹利华鑫近期优选
图文资讯
最新资讯
- 07-01· 中金投行部大摩出售中金
- 07-01· 摩根士丹利招聘6月2日【实
- 07-01· 营养防病圣典
- 07-01· 《博伽梵歌原意》之第十
- 07-01· [不错]斑斓圣典---减肥中常
- 07-01· 武乐圣典《太极武当》:武
- 07-01· 铁血英雄-现阶段战功牌兑
- 07-01· 2011年06月10日【原创】南歌
- 07-01· 【淘宝网信息】- 2010年的
- 07-01· 深圳品牌女装有哪些?