跟着老侯玩编程 跟着老侯玩编程
首页
  • 基础语法
  • 网络编程
  • 设计模式
  • 基础篇
  • 进阶篇
  • 框架篇
  • Redis
  • Alibaba
  • 课程目录
  • 码农宝典
留言
首页
  • 基础语法
  • 网络编程
  • 设计模式
  • 基础篇
  • 进阶篇
  • 框架篇
  • Redis
  • Alibaba
  • 课程目录
  • 码农宝典
留言
  • 基础语法

    • 单元文件
    • 变量和常量
    • 内联变量
    • 基本数据类型
    • 复合数据类型
    • 语句(选择语句)
    • 语句(循环语句)
    • 数组
    • 初识例程
    • 初识面向对象
    • 属性Property
    • 面向对象的方法
    • 指针
    • 接口
    • 匿名函数和委托实现
    • 多态
    • 字符串详解
    • 异常处理
    • 反射机制
    • 泛型容器
      • Collections单元
      • API代码
        • TList
        • TDictionary
      • 参考资料
    • JSON
    • 文件操作
    • Dll创建并调用
    • DLL初始化和退出处理
    • Package
    • 理解消息循环
    • VCL与Windows消息
    • 钩子原理
    • 进程通讯-内存映像
    • 多线程开篇
    • 线程控制
    • 线程同步
  • 网络编程

    • 网络编程基础
    • Delphi网络编程
    • select
    • WSAAsyncSelect
    • WSAEventSelect
  • 设计模式

    • 单例模式
    • 单例模式二
    • 策略模式
    • 简单工厂模式
    • 建造者模式
    • 原型模式
    • 模板方法模式
    • 状态模式
    • 迭代器模式
    • 解释器模式
    • 责任链模式
    • 中介者模式
    • 备忘录模式
    • 命令模式
    • 观察者模式
    • 访问者模式
    • 适配器模式
    • 桥接模式
  • Delphi
  • 基础语法
舞动的代码
2022-05-05
目录

泛型容器

官方描述

Unit that implements generic container classes to group data items in arrays, dictionaries, lists, stacks, queues, and more.

译文:实现泛型容器类的单元,以在数组中对数据项进行分组,词典,列表,堆栈,队列等。

起初在接触到Delphi的时候我以为没有这一部分内容,所有的都要自己实现,此处请原谅我的无知。。。。

关于从那个版本开始支持泛型的,我在官方文档上没有找到对应的说明,也可能是我英语太菜,在官网迷路了。

根据百度得来的结果2007的版本没有(真百度的)支持2009的版本(万一老师的博客上引用的也是这个版本)开始出现,也就是最早支持泛型容器的版本应该是Delphi2009

聊泛型容器避不开的就是泛型的概念,之前看哔哩哔哩的网友留言从泛型一节就是开始懵逼了。其实大可不必,泛型可以理解为一个变量,它的值是一个具体的类型

嗯,其实也可以把它当作孙大圣,它可以变成任何东西

# Collections单元

在这个单元内一共定义了13个容器类,我们在其中甚至可以看到线程队列。那么问题来了,我们需要精通或者学习所有的类吗?答案是否定的

容器类就我个人的理解其实一共有两大表现形式,一种是列表形式的像数组,而另一种形式则以 Key,Value 成对的形式。也就是说我们从种选择两个比较有代表性的类进行学习即可。下面是我选择的两个类

  • System.Generics.Collections.TList:很明显这个是列表

  • System.Generics.Collections.TDictionary:Dictionary这个单词翻译成中文是字典的意思,不知道为啥这么起名,它是K,V形式的代表

注意:在单元内我们还可以看到相似的类例如 System.Generics.Collections.TObjectList<T> 和 System.Generics.Collections.TList<T>区别在于带有Object的类会在删除元素时释放对象,而没有带Object的不会释放

# API代码

针对容器类学习的总原则是围绕增、删、改、查这几个核心的API功能即可,其他的就只能现用现查了,不知道别人写代码是什么习惯,我写代码的时候帮助文档基本上都是开着的。。。

下面是针对两个容器类的代码实现

# TList

实体类(TStudent)代码

type

    TStudent = class
    private
        FName: string;
    public
        property Name: string read FName write FName;
        // 构造方法
        constructor Create; overload;
        // 有参构造方法
        constructor Create(FName: string); overload;
    end;

constructor TStudent.Create;
begin

end;

constructor TStudent.Create(FName: string);
begin
    Self.FName := FName;
end;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

操作类(即增、删、改、查),我没有使用内联,几次想用都删了

uses
    System.Generics.Collections, System.SysUtils;

var
    // 文档上的定义是TList<T>,而我们的定义尖括号中的是TStudent,这就是泛型的用法
    StudentList: TList<TStudent>;
    // 循环中使用获取TList成员
    Stu: TStudent;

begin
    // 初始化学生列表
    StudentList := TList<TStudent>.Create;
    StudentList.add(TStudent.Create('小强'));
    StudentList.add(TStudent.Create('萧蔷'));
    StudentList.add(TStudent.Create('小黑'));
    StudentList.add(TStudent.Create('小白'));
    StudentList.add(TStudent.Create('小黄'));

    // 开始之前输出一次
    for Stu in StudentList do begin

        Writeln('学生信息是:' + Stu.Name);
    end;

    // 泛型容器自带的删除函数,偷个懒
    StudentList.Delete(0);

    // 修改,查询到指定的学生,修改其值即可
    StudentList.Items[0].Name := '小白';


    // 查询,其实和数组的操作没有太大区别
    for Stu in StudentList do begin

        Writeln('学生信息是:' + Stu.Name);
    end;

end.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# TDictionary

此类容器的特点是 key 唯一,并且几乎所有的操作都是根据 key 来的

改造下实体类(TStudent)增加一个属性,代码如下

type

    TStudent = class
    private
        FName: string;
        FId: string;
    public
        property Name: string read FName write FName;
        property Id: string read FId write FId;

        // 构造方法
        constructor Create; overload;
        // 有参构造方法
        constructor Create(FName: string; FId: string); overload;
    end;

constructor TStudent.Create;
begin

end;

constructor TStudent.Create(FName: string; FId: string);
begin
    Self.FName := FName;
end;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

操作类(即增、删、改、查)


{注意单元的引用}
uses
    System.Generics.Collections, System.SysUtils;

var
    // 文档上的定义是TList<T>,而我们的定义尖括号中的是TStudent,这就是泛型的用法
    StudentMap: TDictionary<string, TStudent>;
    // 循环中使用获取TList成员
    Key: string;
    Student,Stu: TStudent;

begin
    // 初始化学生列表
    StudentMap := TDictionary<string, TStudent>.Create;
    // 此处的添加其实并不是太好,根据文档描述,当我们添加的元素的key已经存在会抛出异常
    // 建议使用AddOrSetValue
    StudentMap.add('1001', TStudent.Create('1002', '小强'));
    StudentMap.add('1002', TStudent.Create('1001', '萧蔷'));
    StudentMap.add('1003', TStudent.Create('1003', '小黑'));
    StudentMap.add('1004', TStudent.Create('1004', '小白'));
    StudentMap.add('1005', TStudent.Create('1004', '小黄'));

    // 注意此处获取是key,也就是1001 1002这些东西
    for Key in StudentMap.Keys do begin

        // 获取到key之后,再根据key获取对应value也就是学生对象
        // 这里的获取方式有点儿任性居然要的是一个指针,而不是直接返回
        StudentMap.TryGetValue(Key, Student);
        // 最好判断一下,否则容易出现空指针
        if (Student <> nil) then
            Writeln('学生信息是:' + Student.Name)
    end;

    // 删除元素,无论什么操作都是通过key去操作,因为key是不可以重复的
    StudentMap.Remove('1005');

    // 修改,没有就添加,有就更新
    StudentMap.AddOrSetValue('1004', TStudent.Create('1004', '小黄'));

    // 直接获取value
    for Stu in StudentMap.values do begin
        // 最好判断一下,否则容易出现空指针
        if (Stu <> nil) then
            Writeln('学生信息是:' + Student.Name)

    end;
end.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# 参考资料

  • 万一的博客:https://www.cnblogs.com/del/category/113556.html
  • 官方文档:http://docwiki.embarcadero.com/Libraries/Sydney/en/System.Generics.Collections
反射机制
JSON

← 反射机制 JSON→

Theme by Vdoing | Copyright © 2013-2023 冀ICP备16006233号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×