学习 TList 类的实现[8]
property Items[Index: Integer]: Pointer;
执行 Shift+Ctrl+C 后的代码是:
... TMyList = class(TObject)
private
...
function GetItems(Index: Integer): Pointer;
procedure SetItems(Index: Integer; const Value: Pointer);
public
...
property Items[Index: Integer]: Pointer read GetItems write SetItems;
end; implementation { TMyList } ... function TMyList.GetItems(Index: Integer): Pointer;
begin end; procedure TMyList.SetItems(Index: Integer; const Value: Pointer);
begin end; end.
在 TList 类中, GetItems 方法被命名为 Get; SetItems 方法被命名为 Put. 这里我们就不准备改名了.
分别实现如下:
function TMyList.GetItems(Index: Integer): Pointer;
begin
if (Index < ) or (Index >= FCount) then
raise Exception.CreateFmt('异常:%d', [Index]);
Result := FList^[Index];
end; {同前, 在这里我们也没有触动 Notify 方法, 现在的 TMyList 也没有这个方法}
procedure TMyList.SetItems(Index: Integer; const Value: Pointer);
begin
if (Index < ) or (Index >= FCount) then
raise Exception.CreateFmt('异常:%d', [Index]); if Value <> FList^[Index] then
FList^[Index] := Value;
end;
至此, 我们可以使用 List.Itmes[i] 的方式访问列表中的元素了;
再进一步, 让它成为默认属性吧; 尽管只能选择一个属性为默认属性, 但哪一个属性能比它更重要的呢?
//只需把在 public 区声明的:
property Items[Index: Integer]: Pointer read GetItems write SetItems; //改为:
property Items[Index: Integer]: Pointer read GetItems write SetItems; default;
Items 就是默认属性了, 这样再访问一个元素时, 即可以用: List.Itmes[i]; 也可以使用: List[i]. 默认属性真方便.
看看 TMyList 类目前的全部代码:
unit MyList; interface uses SysUtils; const
MaxListSize = Maxint div ; type
PPointerList = ^TPointerList;
TPointerList = array[..MaxListSize - ] of Pointer; TMyList = class(TObject)
private
FList: PPointerList;
FCount: Integer;
FCapacity: Integer;
procedure SetCapacity(const Value: Integer);
procedure SetCount(const Value: Integer);
function GetItems(Index: Integer): Pointer;
procedure SetItems(Index: Integer; const Value: Pointer);
public
destructor Destroy; override;
function Add(Item: Pointer): Integer;
procedure Clear;
procedure Delete(Index: Integer);
property Capacity: Integer read FCapacity write SetCapacity;
property Count: Integer read FCount write SetCount;
property List: PPointerList read FList;
property Items[Index: Integer]: Pointer read GetItems write SetItems; default;
end; implementation { TMyList } function TMyList.Add(Item: Pointer): Integer;
begin
if FCount = FCapacity then SetCapacity(FCapacity + );
FList^[FCount] := Item;
Result := FCount;
Inc(FCount);
end; procedure TMyList.Clear;
begin
SetCount();
SetCapacity();
end; procedure TMyList.Delete(Index: Integer);
begin
if (Index < ) or (Index >= FCount) then
raise Exception.CreateFmt('非法的 Index:%d', [Index]);
if Index < FCount then
System.Move(FList^[Index+], FList^[Index], (FCount-Index)* SizeOf(Pointer));
Dec(FCount);
end; destructor TMyList.Destroy;
begin
Clear;
inherited;
end; procedure TMyList.SetCapacity(const Value: Integer);
begin
if (Value < FCount) or (Value > MaxListSize) then
raise Exception.CreateFmt('非法数据:%d', [Value]);
if FCapacity <> Value then
begin
ReallocMem(FList, Value * SizeOf(Pointer));
FCapacity := Value;
end;
end; procedure TMyList.SetCount(const Value: Integer);
var
i: Integer;
begin
if (Value < ) or (Value > MaxListSize) then
raise Exception.CreateFmt('非法数据:%d', [Value]);
if Value > FCapacity then SetCapacity(Value);
if Value > FCount then
FillChar(FList^[FCount], (Value - FCount) * SizeOf(Pointer), )
else
for i := FCount - downto Value do
Delete(I);
FCount := Value;
end; function TMyList.GetItems(Index: Integer): Pointer;
begin
if (Index < ) or (Index >= FCount) then
raise Exception.CreateFmt('异常:%d', [Index]);
Result := FList^[Index];
end; procedure TMyList.SetItems(Index: Integer; const Value: Pointer);
begin
if (Index < ) or (Index >= FCount) then
raise Exception.CreateFmt('异常:%d', [Index]); if Value <> FList^[Index] then
FList^[Index] := Value;
end; end.
现在访问元素方便了, 重做上一个测试:
unit Unit1; interface uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls; type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
end; var
Form1: TForm1;
implementation {$R *.dfm} uses MyList; type
TMyRec = record
name: string[];
age : Word;
end; procedure TForm1.FormCreate(Sender: TObject);
var
ListA: TMyList;
r,r1,r2,r3,r4,r5: TMyRec;
begin
ListA := TMyList.Create; r1.name := '张三';
r1.age := ;
ListA.Add(@r1); r2.name := '李四';
r2.age := ;
ListA.Add(@r2); r3.name := '王五';
r3.age := ;
ListA.Add(@r3); r4.name := '孙六';
r4.age := ;
ListA.Add(@r4); r5.name := '候七';
r5.age := ;
ListA.Add(@r5); {获取第三个元素}
//r := TMyRec(ListA.List^[2]^); {这是以前的代码}
r := TMyRec(ListA[]^);
ShowMessageFmt('%s:%d',[r.name, r.age]); {王五:33} {删除第三个元素后再访问第三个元素}
ListA.Delete();
//r := TMyRec(ListA.List^[2]^); {这是以前的代码}
r := TMyRec(ListA[]^);
ShowMessageFmt('%s:%d',[r.name, r.age]); {孙六:44} {现在通过 Items 属性, 不仅可以取值, 还可以赋值}
ListA[] := @r1;
r := TMyRec(ListA[]^);
ShowMessageFmt('%s:%d',[r.name, r.age]); {张三:11} ListA.Free;
end; end.
学习 TList 类的实现[8]的更多相关文章
- 学习 TList 类的实现[4]
现在准备一步步地模拟 TList 类, 建立一个自己的 TMyList. 首先, 这个类中应该包括前面提到的那个 Pointer 数组(TPointerList)的指针(PPointerList): ...
- 学习 TList 类的实现[1]
最近整理了一些函数列表, 算是一个宏观的安排; 等以后再碰到一些函数时就可以放置的更有次序一些. 我对函数与类的理解是: 函数是一个功能模块, 类是一个更强大的功能模块; Delphi 已经提供了很多 ...
- 学习 TList 类的实现[2]
我原来以为 TList 可能是一个链表, 其实只是一个数组而已. 你知道它包含着多大一个数组吗? MaxListSize 个!MaxListSize 是 Delphi 在 Classes 单元定义的一 ...
- 学习 TList 类的实现[6]
实现 TMyList.Add 函数. TList 中的 Add 函数用到了一个 Grow 方法, 它的原理是元素越多就为以后准备更多内存, 我们这里省略为预留 4 个元素的内存; TList 中的 A ...
- 学习 TList 类的实现[5]
先来实现 TMyList.SetCapacity. 马上会想到下面代码: procedure TMyList.SetCapacity(const Value: Integer); begin if ...
- 学习 TList 类的实现[3] - 不能回避的话题: 内存分配
在 Delphi 中, 几乎所有的类型都有对应的指针类型, 譬如: Char PChar Word PWORD Double PDouble TPoint PPoint 甚至一种类型对应这着几种指针类 ...
- 学习 TList 类的实现[7]
总结目前 TMyList 已具备的功能(3 个方法.3 个属性): Add: 添加; Delete: 删除; Clear: 清空;Count: 元素总数;Capacity: 已存在的所有元素位置数;L ...
- Java虚拟机JVM学习07 类的卸载机制
Java虚拟机JVM学习07 类的卸载机制 类的生命周期 当Sample类被加载.连接和初始化后,它的生命周期就开始了. 当代表Sample类的Class对象不再被引用,即不可触及时,Class对象就 ...
- Java虚拟机JVM学习04 类的初始化
Java虚拟机JVM学习04 类的初始化 类的初始化 在初始化阶段,Java虚拟机执行类的初始化语句,为类的静态变量赋予初始值. 在程序中,静态变量的初始化有两种途径: 1.在静态变量的声明处进行初始 ...
随机推荐
- [svc]mousedos网络批量部署xp
小时候对这个东西很好奇,不知道什么原理.一直觉得很好玩.现在研究了下,总结如下 软件的操作步骤很讲究,稍微不慎,则就需要重新来过 知识点: 1,掌握诺顿ghost分区为gh文件 2,学会清理至一个干净 ...
- 【Android】11.5 创建和管理Fragments
分类:C#.Android.VS2015: 创建日期:2016-02-22 一.简介 想要管理activity中的fragment,可以用FragmentManager类来实现.通过在activity ...
- Linux环境下搭建测试环境(LAMP详细说明)
一.安装虚拟机与CentOS7 传送门:https://www.cnblogs.com/mrgavin/p/9372393.html 注意:以下安装,我都是用的root权限. 二.安装Apache1. ...
- 随笔记:Python于Windows下初实践,及使用Connector/Python连接MySQL
有一同事要离职了,我负责交接一个用Python同步数据的项目. 之前木有做过Python,周休,做个简单的查询数据库,小练一下手. 包含: 安装 连接.查询MySQL 列表 元组 for循环 whil ...
- 百度编辑器UEditor不能插入音频视频的解决方法
引用:https://my.oschina.net/u/379795/blog/787985 xssFilter导致插入视频异常,编辑器在切换源码的过程中过滤掉img的_url属性(用来存储视频url ...
- 【C#/WPF】键盘事件
需求:按下回车键,触发事件. 搜MSDN时,看到的键盘事件是System.Windows.Forms里的,在WPF中没法用: https://msdn.microsoft.com/zh-tw/libr ...
- Java并发编程()阻塞队列和生产者-消费者模式
阻塞队列提供了可阻塞的put和take方法,以及支持定时的offer和poll方法.如果队列已经满了,那么put方法将阻塞直到有空间可用:如果队列为空,那么take方法将会阻塞直到有元素可用.队列可以 ...
- windows 搭建 subversion+TortoiseSVN
1.版本 (a)Apache 2.2.25:httpd-2.2.25-win32-x86-no_ssl.msi (b)Subversion:Setup-Subversion-1.8.5.msi (c) ...
- C语言 static静态变量
静态变量类型说明符是static. 静态变量属于静态存储方式,其存储空间为内存中的静态数据区(在 静态存储区内分配存储单元),该区域中的数据在整个程序的运行期间一直占用这些存储空间(在程序整个运行期间 ...
- phpstudy+php5.2+mssql2008
我勒个去.... <?php $server ="XEJMZWMDIXE9CIJ"; //服务器IP地址,如果是本地,可以写成localhost $uid ="&q ...