quicklib 是一个快速开发库
quicklib是一个快速开发库,它提供了诸如automapper、linq、ioc依赖注入、memorycache、计划任务、json和yml配置、序列化程序等多种功能。这个库特别支持delphi和firemonkey的多平台开发,包括windows、linux、android、osx和ios。同时,quicklib也支持freepascal,使得开发人员能够更轻松地构建跨平台应用程序并提高生产力。
功能领域:
- 映射(mapping): 将一个类的字段映射到另一个类,复制对象等。
- 配置(config): 将配置作为对象使用,并从/向文件(json/yaml)或windows注册表加载/保存。
- 序列化(serialization): 将对象序列化到/从json/yaml。
- 调度(scheduling): 以独立线程启动任务,并具有重试策略。
- 线程(threading): 简化多线程后台任务的运行和控制,线程安全的列表、队列等
- 数据(data): 灵活的数据交换和存储,允许多种输入输出类型。
- 云(cloud): 简化云azure/amazon文件管理,发送电子邮件等。
- 查询(querying): 索引列表,可搜索列表和用于通用列表和数组的linq查询系统。
- 基准测试(benchmark): 经过的时间控制和基准测试功能。
- 文件系统(filesystem): 进程和服务控制,文件修改监视器和助手等...
- 失败控制(failcontrol): 失败和重试策略。
- 缓存(caching): 缓存字符串或对象,以便稍后快速检索。
- 模板(templating): 使用字典进行简单的字符串模板化。
- 调试(debuging): 用于调试代码的工具。
- 参数(parameters): 使用命令行参数。
主要单元描述:
- quick.commons: 开发人员日常工作中经常需要的功能。
- quick.appservice: 允许控制台应用程序以控制台模式或服务模式运行相同的代码,从而简化调试任务。
- quick.azure/amazon: 简化了与azure和amazon云存储的blob交互。
- quick.network: cidr和ip范围功能。
- quick.chrono: 计时器和基准测试一段代码很简单。
- quick.console: 使用颜色等将日志消息写入控制台...
- quick.log: 以详细级别和每日或最大空间轮换方式记录到磁盘或内存。
- quick.config: 将配置加载/保存为json或yaml文件或windows注册表项,并将其作为对象管理。
- quick.filemonitor: 监视文件的更改并抛出事件。
- quick.jsonutils: 用于处理json对象的工具。
- quick.smtp: 用两行代码发送电子邮件。
- quick.threads: 线程安全类,具有重试策略的调度和后台任务。
- quick.process: 管理windows进程。
- quick.services: 管理windows服务。
- quick.format: 字符串格式。
- quick.rtti.utils: 简化与rtti的工作。
- quick.jsonserializer: 将对象序列化到/从json文本。您可以定义是否将处理公开或发布的属性(仅delphi,fpc rtti仅支持已发布的属性)
- quick.automapper: 将一个类的字段映射到另一个类。允许自定义映射以匹配不同的字段,以及手动转换/转换字段的自定义映射过程。
- quick.jsonrecord: 用作dto类,包含json序列化和映射功能。
- quick.lists: 具有索引或搜索功能的改进列表。
- quick.value flexvalue存储任何数据类型,并允许使用集成运算符和autofrees将其传递给其他类。
- quick.arrays: 改进的数组。
- quick.yaml: yaml对象结构。
- quick.yaml.serializer: 将对象从/序列化为yaml。
- quick.expression: 使用表达式评估对象属性。
- quick.linq: 对任何tobjectlist,tlist,tarray和txarray进行linq查询,执行类似sql语法的复杂where选择,更新和排序列表。
- quick.memorycache: 缓存具有过期时间的对象/信息,以避免每次需要时都生成这些信息(数据库查询,难以计算的信息等)。
- quick.collections: 集合改进,如具有linq继承的ilist和iobjectlist。
- quick.pooling: 创建对象池以避免外部资源消耗殆尽和开销。
- quick.template: 使用字典或委托替换字符串模板。
- quick.debug.utils: 简单的调试和代码基准测试工具。
- quick.parameters: 将命令行参数作为一个类来处理。
- quick.url.utils: 简单的url操作
- quick.regex.utils: 常用的regex比较(电子邮件验证,密码复杂性等)
- quick.conditions: 流畅风格的前后条件验证。
quick.appservice:
允许控制台应用程序以控制台模式或服务模式运行相同的代码,从而简化调试任务。
if not appservice.isrunningasservice then
begin
...你的代码以控制台模式运行
end
else
begin
appservice.servicename := 'myservice';
appservice.displayname := 'myservicesvc';
//你可以将匿名方法传递给事件
appservice.onstart := procedure
begin
...你的启动代码
end;
appservice.onexecute := yourexecutefunction;
appservice.onstop := yourstopfunction;
appservice.checkparams;
end;
quick.azure/amazon:
简化了与azure和amazon云存储的blob交互。
//连接到azure blob存储
quickazure := tquickazure.create(azureaccountname, azureaccountkey);
//将blob文件下载到流中
done := quickazure.getblob('mycontainer', 'myfile.jpg', responseinfo, mystream);
//检查是否存在文件夹
found := existfolder('mycontainer', '/public/documents/personal');
//列出以特定模式开头的blobs(递归或非递归)
for azblob in listblobs('mycontainer', '/public/documents', recursive, responseinfo) do
begin
if azblob.size > 1000 then showmessage(azblob.name);
end;
quick.network:
提供cidr和ip范围功能。
//将ip字符串转换为整数
ipv4toint('192.168.1.10');
//获取子网范围的第一个和最后一个ip
getiprange('192.168.100.0', '255.255.255.0', lowip, highip);
quick.commons:
开发人员日常工作中经常需要的函数。
//将utc时间tdatetime转换为本地日期时间
utctolocaltime(myutctime);
//生成一个长度为10的随机密码,包含字母数字和符号。
randompassword(10, [pfincludenumbers, pfincludesigns]);
//将短语中的每个单词首字母大写
capitalizeall('the grey fox'); //返回 "the grey fox"
//简单的tcounter和ttimecounter用于循环
counter := tcounter;
counter.init(200);
timecounter : ttimecounter;
timecounter.init(10000);
while true do
begin
inc(n);
{你的过程处理代码在这里}
//每200步写入控制台
if counter.check then writeln(format('processed %d entries', [n]));
//每10秒写入控制台
if timecounter.check then writeln('im working...');
end;
quick.chrono:
计时器和代码基准测试很简单。
//获取代码部分执行所消耗的时间
chrono := tchronometer.create(false);
chrono.start;
...你需要基准测试的代码
chrono.stop;
//以长时间格式显示经过的时间(例如2小时10分钟)
showmessage(chrono.timeelapsed(true));
//以短时间格式显示经过的时间(例如02:10:00)
showmessage(chrono.timeelapsed(false));
//获取进程的基准测试信息
chrono := tchronobenchmark.create;
chrono.totalprocess := 100000;
for i := 1 to 10000 do
begin
{你的进程代码在这里}
chrono.currentprocess := i;
//显示你的进程预计需要的时间,格式为x小时x分钟x秒
writeln(chrono.estimatedtime(true));
//显示你的进程处理速度:每秒处理的项数
writeln(format('items processed %d/sec', [chrono.speed]));
end;
writeln(chrono.elapsedtime(false)); //以00:00:00格式显示总经过时间
quick.console:
将日志消息以不同颜色等写入控制台。
//定义需要的输出级别
console.verbose := log_debug;
//以红色在控制台上写行
cout('error x', eterror);
//以绿色格式化输出行
coutfmt('proccess %s finished', [proccesname], etsuccess);
//写整数
cout(12348);
//连接quicklog并一行代码同时写入磁盘和屏幕(具有独立的详细级别)
myquicklog := tquicklog.create;
myquicklog.verbose := log_all;
console.verbose := log_onlyerrors;
console.log := myquicklog;
quick.log:
记录到磁盘或内存,具有详细的日志等级和每日或最大空间轮换功能。
// 在开始时写入包含运行路径、应用程序名称、调试模式、用户等信息的页眉
log.showheader := true;// 设置20mb时轮换的日志
log.setlog('.\mylog.log',false,20);// 写入一条错误信息
log.add('error x',eterror);// 写入格式化的错误信息
log.add('error is %s',[errorstr],eterror);quick.config:
以json、yaml文件或windows注册表项的形式加载/保存配置。从tappconfigjson、tappconfigyaml或tappconfigregistry创建一个派生类,并添加将加载/保存的已发布的属性。当检测到文件更改时,可以重新加载文件配置。// 创建一个类继承
tmyconfig = class(tappconfigjson)
private
fname : string;
fsurname : string;
fstatus : integer;
published
property name : string read fname write fname;
property surname : string read fsurname write fsurname;
property status : integer read fstatus write fstatus;
end;// 将配置创建为json文件
// 在您的uses中添加quick.config.json
myconfig := tmyconfig.create('config.json');
myconfig.provider.createifnotexists := true;
myconfig.provider.reloadiffilemodified := true;
myconfig.name := 'john';
myconfig.surname := 'smith';
// 加载
myconfig.load;
// 保存
myconfig.save;// 将配置创建到windows注册表中
// 在您的uses中添加quick.config.registry
myconfig := tmyconfig.create;
// 将注册表定义为hkey_current_user\software\myapp
myconfig.hroot := hkey_current_user;
myconfig.mainkey := 'myapp';
myconfig.name := 'john';
myconfig.surname := 'smith';
// 加载
myconfig.load;
// 保存
myconfig.save;// 创建一个没有默认提供者的自定义配置
tmyconfig = class(tappconfig)
... 您的属性
end;myconfig := tmyconfig.create(tappconfigjsonprovider.create('.\config.json');
quick.filemonitor:
监视文件的更改并触发事件。
filemonitor.filename := '.\myfile.txt'; // 每2秒检查一次文件更改 filemonitor.interval := 2000; // 监视文件被删除或修改的事件 filemonitor.notifies := [mnfilemodified, mnfiledeleted)]; filemonitor.onfilechange := myfilechangefunction; filemonitor.enabled := true;
quick.jsonutils:
用于处理json对象的工具。
// 当在uses中声明单元时,tobject helper允许将所有对象从/加载到json字符串 myobject.fromjson := jsonstring; mystring := myobject.tojson;// 您可以使用clone函数克隆简单对象 myobject1.clone(myobject2);
quick.smtp:
用两行代码发送电子邮件。
// 发送电子邮件
smtp := tsmtp.create('mail.domain.com',25,false);
smtp.sendmail('my@email.com','to@email.com','email subject','my message body');// 您可以定义更高级的选项
smtp.sendername := 'john';
smtp.from := 'my@email.com';
smtp.recipient := 'one@email.com,two@email.com';
smtp.subject := 'email subject';
smtp.addbodyfromfile := '.\body.html';
smtp.cc := 'other@email.com';
smtp.bcc := 'more@email.com';
smtp.attachments.add('.\notes.txt');
smtp.sendmail;
quick.threads:
线程安全类。
tthreadedqueuecs: 使用临界区的tthreadedqueue版本。
tthreadobjectlist: 线程安全的对象列表。
tthreadedqueuelist: 线程安全的队列列表。支持自动增长和临界区。
tanonymousthread: 创建匿名线程,定义非链式的execute和onterminate方法。如果代码需要更新ui,请使用execute_sync和onterminate_sync方法。
- execute: 指定启动时执行的代码。
- execute_sync: 与execute类似,但使用同步线程方法运行代码(避免如果代码更新ui时出现问题)。
- onterminate: 指定任务完成时执行的代码。
- onterminate_sync: 与onterminate类似,但使用同步线程方法运行代码(避免如果代码更新ui时出现问题)。
- start: 启动线程执行。
// 简单的匿名线程
tanonymousthread.execute(
procedure
var
i : integer;
begin
for i := 0 to 10 do cout('working %d',[i],ettrace);
cout('executed thread',etsuccess);
end)
.onterminate(
procedure
begin
cout('terminated thread',etsuccess);
cout('press <enter> to exit',etinfo);
end)
.start;
truntask: 启动一个自动释放的单任务线程,具有故障和重试控制策略。可以在代码中传递和创建参数。
- 定义要执行的代码:
- execute: 指定任务名称、传递给匿名方法的参数(如果ownedparams=true,任务将在终止时释放参数)以及将要执行的方法。
- execute_sync: 与execute类似,但使用同步线程方法运行代码(避免如果代码更新ui时出现问题)。
- setparameter: 定义任务所需的值或对象。
- 定义控制事件:
- oninitialize: 在主执行任务之前运行指定的代码(此代码仅运行一次,onexecute可以重试多次)
- onretry: 当执行失败时指定要运行的代码,并决定是否需要重试或取消后续重试。
- onterminate: 指定任务完成时执行的代码。
- onterminate_sync: 与onterminate类似,但使用同步线程方法运行代码(避免如果代码更新ui时出现问题)。
- onexception: 当任务引发异常时指定要执行的代码。
- 定义故障/重试策略:
- retryforever: 如果执行失败,代码将无限次重试,直到任务执行成功。
- retry: 如果执行失败,代码将重试x次。
- waitandretry: 如果执行失败,代码将重试x次,并在每次重试之前等待x毫秒。您可以指定重试次数和重试之间的等待时间。
- run: 启动任务执行。
truntask.execute(
procedure(task : itask)
var
stream : tstringstream;
response : ihttprequestresponse;
begin
stream := tstringstream.create;
try
response := tjsonhttpclient(task['httpclient'].asobject).get(task['url']);
task.result := response.statuscode;
if response.statuscode <> 200 then raise exception.create(response.statustext);
finally
stream.free;
end;
end)
.setparameter('httpclient',(tjsonhttpclient.create),true)
.setparameter('url','https://mydomain.com/testfile')
.waitandretry(5,250,2)
.onretry(
procedure(task : itask; aexception : exception; var vstopretries : boolean)
begin
//if error 404 don't try to retry request
if task.result = 404 then vstopretries := true;
end)
.onexception(
procedure(task : itask; aexception : exception)
begin
coutfmt('exception downloading (error: %s / statuscode: %d)...',[aexception.message,task.result.asinteger],eterror);
end)
.onterminated(
procedure(task : itask)
begin
if task.done then coutfmt('download "%s" finished ok',[task['url'].asstring],etsuccess)
else coutfmt('download "%s" failed after %d retries',[task['url'].asstring,task.numretries],eterror);
end)
.run;
tbackgroundstasks: 在后台启动任务,允许一定数量的并发工作线程,并具有故障和重试控制策略。如果代码需要更新ui,请使用addtask_sync和onterminate_sync方法。
- 添加要执行的任务:
- addtask: 指定任务名称、传递给匿名方法的参数(如果ownedparams=true,任务将在过期时释放参数)以及将要执行的方法。
- addtask_sync: 与addtask类似,但使用同步线程方法运行代码(避免如果代码更新ui时出现问题)。
- setparameter: 定义任务所需的值或对象。每个参数都将在匿名方法中作为task[
<name>]或task.[index]访问。
- 定义控制事件:
(与truntask类似,此处省略) - 定义故障/重试策略:
(与truntask类似,此处省略) - 开始执行:
- start: 开始执行任务。
backgroundtasks := tbackgroundtasks.create(10);
for i := 1 to 100 do
begin
mytask := tmytask.create;
mytask.id := i;
mytask.name := 'task' + i.tostring;
backgroundtasks.addtask([mytask],false,
procedure(task : itask)
begin
cout('task %d started',[tmytask(task.param[0].asobject).id],etdebug);
tmytask(task.param[0].asobject).dojob;
end
).waitandretry([250,2000,10000])
).onexception(
procedure(task : itask; aexception : exception)
begin
cout('task %d failed (%s)',[tmytask(task.param[0].asobject).id,aexception.message],eterror);
end
).onterminated(
procedure(task : itask)
begin
cout('task %d finished',[tmytask(task.param[0].asobject).id],etdebug);
tmytask(task.param[0].asobject).free;
end
).run;
end;
backgroundtasks.start;
tscheduledtasks: 定时器的替代方案。您可以分配具有开始时间、重复选项、到期日期和故障及重试控制策略的任务。如果代码需要更新ui,请使用addtask_sync、onterminate_sync和onexpired_sync方法。
您可以为执行、异常、终止和到期事件分配匿名方法。
- 添加要执行的任务:
(与truntask和tbackgroundtasks类似,此处省略) - 定义控制事件:
(与truntask类似,但增加了onexpire和onexpire_sync) - 定义何时开始任务:
- startnow: 立即启动任务。
- startat: 任务启动的日期和时间。
- ...(其他开始选项,此处省略)
- 定义是否需要重复或不重复(如果未定义之前的startat、starton等,任务将立即执行):
- runonce: 任务仅执行一次。
- repeatevery: 可以指示重复步骤的时间间隔和到期日期。
- ...(其他重复选项,此处省略)
- 定义故障/重试策略:
(与truntask类似,此处省略) - 启动/停止调度器:
- start: 启动调度器。
- stop: 停止调度器。
myjob := tmyjob.create;
myjob.name := format('run at %s and repeat every 1 second until %s',[datetimetostr(scheduleddate),datetimetostr(expirationdate)]);
scheduledtasks.addtask('task1',[myjob],true,
procedure(task : itask)
begin
cout('task "%s" started',[tmytask(task.param[0]).name],etdebug);
tmyjob(task.param[0]).dojob;
end
).onexception(
procedure(task : itask; aexception : exception)
begin
cout('task "%s" failed (%s)',[tmyjob(task.param[0]).name,aexception.message],eterror);
end
).onterminated(
procedure(task : itask)
begin
cout('task "%s" finished',[tmyjob(task.param[0]).name],etdebug);
end
).onexpired(
procedure(task : itask)
begin
cout('task "%s" expired',[tmyjob(task.param[0]).name],etwarning);
end
).startat(scheduleddate
).repeatevery(1,ttimemeasure.tmseconds,expirationdate);
scheduledtasks.start;
itask: 传递给truntask、tbackgroundtasks和tscheduledtasks的每个任务事件的接口。
- numworker: 返回分配给执行任务的工作线程数。
- result: 可以存储任何值类型(tflexvalue类似于变体类型)
- param[name]: 可以存储传递给任务的参数或在每个传递给事件的匿名方法中动态创建的参数。
- param[index]: 可以存储传递给任务的参数或在每个传递给事件的匿名方法中动态创建的参数。
- done: 如果任务没有错误地执行,则返回true。
- failed: 如果任务失败,则返回true。
- idtask: 定义的任务id。
- numretries: 已完成的重试次数。
- maxretries: 在将任务标记为失败之前允许的最大重试次数。
- lastexception: 返回失败任务的最后一个异常。
- circuitbreaked: 如果已达到最大重试次数或在onretry事件中用户取消了重试,则返回true。
- isenabled: 返回任务的状态。
quick.faultcontrol:
管理失败和重试策略,定义最大重试次数、重试之间的等待时间和熔断机制。
quick.process:
管理windows进程。
// 终止explorer进程
killprocess('explorer.exe');
// 判断一个应用程序是否正在运行
if isprocessrunning('explorer.exe') then showmessage('explorer正在运行!');
// 获取运行exe的用户名
writeln('explorer.exe由以下用户打开:' + getprocessuser('explorer.exe'));
// 使用20秒的超时获取窗口句柄
if findwindowtimeout('mainwindow',20) then writeln('检测到窗口');
quick.services:
管理windows服务。
// 检测服务是否已安装
if not serviceispresent('localhost','mysvc') then raise exception.create('服务未安装!');
// 启动服务
servicestart('localhost','mysvc');
// 卸载服务
serviceuninstall('mysvc');
quick.format:
字符串格式化。
// 将字节格式化为mb、gb、tb... formatbytes(50000) // 显示 50kb formatbytes(90000000) // 显示 90mb
quick.jsonserializer:
将对象序列化为json文本或从json文本反序列化为对象。您可以定义是否处理公开或已发布的属性(仅delphi,fpc rtti仅支持已发布的属性)。
json := '{"name":"peter","age":30}';
serializer := tjsonserializer.create(tserializelevel.slpublishedproperty);
try
serializer.jsontoobject(user,json);
finally
serializer.free;
end;
quick.automapper:
将一个类的字段映射到另一个类。允许自定义映射以匹配不同的字段,并允许自定义映射过程以手动转换字段。
// 将user1的值映射到user2
tmapper<tuser2>.map(user);
// 自定义映射
automapper := tautomapper<tuser,tuser2>.create;
// 选项1:您可以定义自动映射不同名称的属性
automapper.custommapping.addmap('cash','money');
automapper.custommapping.addmap('id','iduser');
// 选项2:您可以决定手动修改每个属性或允许自动映射某些属性
automapper.ondomapping := procedure(const asrcobj : tuser; const atargetname : string; out value : tflexvalue)
begin
if atargetname = 'money' then value := asrcobj.cash * 2
else if atargetname = 'iduser' then value := asrcobj.id;
end;
// 选项3:您可以在自动映射完成后修改某些属性
automapper.onaftermapping := procedure(const asrcobj : tuser; atgtobj : tuser2)
begin
atgtobj.money := asrcobj.cash * 2;
atgtobj.iduser := asrcobj.id;
end;
user2 := automapper.map(user);
quick.jsonrecord:
用作dto类,包含json序列化和映射功能。
type
tuser = class(tjsonrecord)
private
fname : string;
fage : integer;
published
property name : string read fname write fname;
property age : integer read fage write fage;
end;
var
user, user2 : tuser;
begin
user := tuser.create;
// 展示为json字符串
writeln(user.tojson);
// 映射到其他类
user.mapto(user2);
writeln(user2.tojson);
// 从文件加载
user.loadfromfile('.\user.json');
// 保存到文件
user2.savetofile('.\user2.json');
end;
quick.lists:
带有索引或搜索功能的改进列表。
- tindexedobjectlist: 允许通过对象属性或字段进行快速哈希搜索。
- tsearchobjectlist: 允许通过对象属性或字段进行迭代搜索。
var
users : tindexedobjectlist<tuser>;
begin
users := tindexedobjectlist<tuser>.create(true);
// 根据属性"name"创建索引
users.indexes.add('name','name',tclassfield.cfproperty);
// 根据私有字段"id"创建索引
users.indexes.add('id','fid',tclassfield.cffield);
// 通过"name"索引获取用户
writeln(users.get('name','peter').surname);
end;
quick.value
flexvalue可以存储任何数据类型,并允许使用集成操作符和自动释放功能传递给其他类。
var value : tflexvalue; str : string; num : integer; begin value := 'hello'; str := value; value := 123; num := value; end;
quick.arrays:
改进的数组。
txarray: 带有类似tlist方法的数组。
(注意:下面的代码段似乎被错误地复制了 tindexedobjectlist的示例,这里应该展示 txarray的使用。)
var users : txarray<tuser>; begin users := txarray<tuser>.create; users.add(user); // 假设user已经是一个tuser类型的对象 // ... 其他txarray的操作 end;
tflexarray: 可以存储不同值类型的数组,类似于tlist。
var
flexarray : tflexarray;
begin
flexarray.add(10);
flexarray.add('hello');
user := tuser.create;
try
user.name := 'joe';
flexarray.add(user);
cout('integer item = %d',[flexarray[0].asinteger],etinfo);
cout('string item = %s',[flexarray[1].asstring],etinfo);
cout('record item = %s',[tuser(flexarray[2]).name],etinfo);
finally
user.free;
end;
end;
tflexpairarray: 可以存储不同值类型的数组,并可以通过项目名称进行搜索,类似于tlist。
var
flexarray : tflexpairarray;
begin
flexarray.add('onenumber',10);
flexarray.add('other','hello boy!');
user := tuser.create;
try
user.name := 'joe';
flexarray.add('myuser',user);
cout('integer item = %d',[flexarray.getvalue('onenumber').asinteger],etinfo);
cout('string item = %s',[flexarray.getvalue('other').asstring],etinfo);
cout('record item = %s',[tuser(flexarray.getvalue('myuser')).name],etinfo);
finally
user.free;
end;
end;
quick.yaml:
yaml对象结构。
tyamlobject: yaml对象是一个yaml值对的数组。
// 从yaml文本创建yaml对象
yamlobj.parseyamlvalue(ayaml);
// 添加一个对
yamlobj.addpair('name','mike');
// 显示为yaml结构
writeln(yamlobj.toyaml);
tyamlarray: 对象或标量的数组。
yamlarray.addelement(tyamlpair.create('age',30));
yamlobj.addpair('myarray',yamlarray);
tyamlpair: 名称-值对。值可以是对象、数组或标量。
n := yamlobj.getpair('name').value as tyamlinteger;
quick.yaml.serializer:
将对象序列化/反序列化为yaml。
// 序列化 text := yamlserializer.objecttoyaml(obj); // 反序列化 yamlserializer.yamltoobject(obj, yamltext);
quick.expression:
使用表达式评估对象属性或单个值。
if texpressionparser.validate(user, '(age > 30) and (dept.name = "financial")') then begin // 执行一些操作 end; if texpressionparser.validate(user, '(20 > 30) or (5 > 3)') then begin // 执行一些操作 end;
quick.linq:
对任何 tobjectlist<t>、tlist<t>、tarray<t>和 txarray<t>执行linq查询,通过类似sql语法的复杂where子句进行select、更新和排序列表。where子句使用命名空间来确定嵌套属性。linq可以在属性数组中搜索元素。
现在包括一个 tarray<string>助手,用于在数组中添加、删除和通过正则表达式搜索。
- from: 要使用的数组、xarray或tobjectlist。
- where: 搜索表达式。可以使用点来定义属性路径。
- selectall: 返回匹配where子句的对象数组。
- selecttop: 返回匹配where子句的前x个对象。
- selectfirst: 返回匹配where子句的第一个对象。
- selectlast: 返回匹配where子句的最后一个对象。
- orderby: 定义返回列表的顺序。
- update: 更新匹配where子句的字段。
- delete: 删除匹配where子句的对象。
- count: 返回匹配where子句的元素数量。
// 多条件选择
for user in tlinq<tuser>.from(userslist).where('(name = ?) or (surname = ?) or (surname = ?)', ['peter', 'smith', 'huan']).select do
begin
// 执行一些操作
end;
// 选择并更新字段
tlinq<tuser>.from(userlist).where('surname like ?', ['%son']).selectfirst.name := 'robert';
// 选择顶部并按字段排序
for user in tlinq<tuser>.from(userlist).where('age > ?', [18]).selecttop(10).orderby('name') do
begin
// 执行一些操作
end;
// 按条件更新字段
tlinq<tuser>.from(userlist).where('name = ?', ['peter']).update(['name'], ['joe']);
// 计数结果
numusers := tlinq<tuser>.from(userlist).where('(age > ?) and (age < ?)', [30, 40]).count;
quick.httpserver:
tcustomhttpserver是一个简单的接口httpserver,具有自己的httprequest和httpresponse实现,允许轻松更改httpserver引擎。
您可以启用自定义错误页面以返回自定义页面和动态错误页面。
thttpserver是indyhttpserver的实现,但您可以定义自己的实现。
tmyhttpserver = class(thttpserver) public procedure processrequest(arequest: ihttprequest; aresponse: ihttpresponse); override; end; procedure tmyhttpserver.processrequest(arequest: ihttprequest; aresponse: ihttpresponse); begin aresponse.contenttext := 'hello world!'; end;
quick.memorycache:
使用过期时间缓存对象或字符串,以避免每次需要时都生成这些信息(数据库查询、难以计算的信息等)。tmemorycache允许缓存对象和字符串。泛型版本tmemorycache <t>仅允许缓存定义的类型。
- 创建:可以定义清除间隔、序列化和压缩引擎。默认情况下,它使用json进行序列化并使用gzip进行压缩。
// 创建具有10秒清除间隔的memorycache cache := tmemorycache.create(10); // 为特定类型创建memorycache cache := tmemorycache<tmyobj>.create;
- 压缩:启用/禁用缓存数据压缩。
- cachedobjects:返回当前缓存中的对象数量。
- cachesize:返回当前缓存中所有对象的字节大小。实际使用的内存取决于内存管理器或架构。此值是数据字节的实际大小。
- purgeinterval:清除作业尝试查找已过期对象以从缓存中删除的时间间隔(默认值为20秒)。
- oncacheflushed:当缓存被刷新时。
- onbeginpurgerjob:当清除作业开始时。
- onendpurgerjob:当清除作业结束时。
- flush:删除所有缓存对象。
- setvalue:将对象添加到缓存。可以指示过期日期或毫秒数来过期。如果没有定义,缓存将是无限的。memorycache可以存储对象或字符串。
// 将字符串设置到缓存中,没有过期时间
cache.setvalue('mystring', 'hello world');
// 将字符串设置到缓存中,10秒后过期
cache.setvalue('mystring', '这个缓存将在10秒后过期');
// 将对象设置到缓存中
cache.setvalue('obj1', valueobj);
- trygetvalue:尝试从缓存中获取对象。如果对象不存在或已过期,则返回false。
// 获取字符串查询结果
cache.getvalue('query12');
// 获取整数
cache.trygetvalue<integer>('number', valueint);
// 获取对象
cache.trygetvalue('obj1', valueobj);
- removevalue:从缓存中删除对象。
- 缓存引擎提供程序:
- tcacheserializerjson:使用json序列化缓存数据。
- tcachecompressorgzip:使用gzip压缩缓存数据。
- tcachecompressorlzo:使用lzo压缩缓存数据。
// 创建具有20秒清除间隔并使用lzo引擎压缩的memorycache cache := tmemorycache.create(10, nil, tcachecompressorlzo.create);
quick.ioc:
控制反转管理器允许自动创建接口或实例化对象,或在构造函数类中自动注入它们,以避免依赖关系。
创建一个容器来管理依赖注入。
ioccontainer := tioccontainer.create;
注册类型:
在注入之前,您需要注册类型。类型可以作为singleton或transient注册。
singleton:生命周期将是所有注入的一个单一实例,类似于全局变量。
transient:生命周期将是每次注入的一个新实例。
将接口类型作为transient注册到容器中:
ioccontainer.registertype<imultservice, tmultservice>.astransient;
将接口类型作为singleton注册,并委托构造:
ioccontainer.registertype<isumservice, tsumservice>.assingleton.delegateto(
function : tsumservice
begin
result := tsumservice.create;
end
);
注册实例:
将命名实例对象作为transient注册,并委托构造:
ioccontainer.registerinstance<tdivideservice>('one').astransient.delegateto(
function : tdivideservice
begin
result := tdivideservice.create(true);
end
);
注册选项:
注册ioptions(仅适用于singleton):
ioccontainer.registeroptions<tmyoptions>(myoptions);
解析类型:
abstractfactory:
尝试使用依赖注入解析所有创建方法参数来创建类。
myclass := ioccontainer.abstractfactory<tmybaseclass>(tmyclass);
解析接口依赖:
multservice := ioccontainer.resolve<imultservice>; result := multservice.mult(2, 4);
解析实例:
解析命名实例依赖:
divideservice := ioccontainer.resolve<tdivideservice>('other');
result := divideservice.divide(100, 2);
接口实例将自动释放,但实例依赖项仅当定义为singleton时才会被释放,transient实例将由代码销毁。#3
quick.options:
您可以将部分定义为类,并将其保存为单个文件设置。其工作方式类似于dotnet options。选项文件可以是json或yaml格式。
定义从toptions继承的选项类,所有已发布的属性都将被加载/保存。
创建选项容器,使用jsonserializer并在更改时重新加载:
options := toptionscontainer.create('.\options.conf', tjsonoptionsserializer.create, true);
向容器选项添加一个部分:
options.addsection<tloggingoptions>('logging');
配置选项:
您可以定义要保存到文件中的部分名称,并委托配置默认设置和验证值:
options.addsection<tloggingoptions>('logging').configureoptions(
procedure(aoptions: tloggingoptions)
begin
aoptions.path := 'c:\';
end
).validateoptions;
验证选项:
验证选项允许验证选项设置是否在定义的范围内。此验证需要先在toptions类中的属性上分配自定义属性。
- stringlength(max, messagestr): 允许在字符串属性中定义最大长度,如果长度大于最大值,则返回messagestr。
- range(min, max, messagestr): 允许定义允许的最小值和最大值范围,如果值超出边界,则返回messagestr。
tloggingoptions = class(toptions)
private
fpath : string;
published
[required, stringlength(255, 'path too long')]
property path : string read fpath write fpath;
[range(0.0, 5.2)]
property level : double read flevel write flevel;
end;
使用选项:
检索选项部分:
loggingoptions := options.getsection<tloggingoptions>; loggingoptions.path := 'c:\path';
使用ioptions:
ioptions是一个可注入依赖的toptions接口。您可以使用ioccontainer.registeroptions <toptions>注册它以使其可注入到构造函数方法中。
uioptions := options.getsectioninterface<tuioptions>.value; uioptions.windowcolor := clblue;
加载/保存选项:
从文件设置中加载选项:
options.load;
将选项保存到文件设置:
options.save;
如果您在创建容器时定义了reloadonchanged参数为true,则每次文件设置更改时,配置都将重新加载。如果您需要控制何时重新加载,可以监听事件:
options.onfilemodified := procedure
begin
cout('detected config file modification!', etwarning);
end;
quick.pooling:
定义连接池、线程池或您想要控制的任何对象池,以避免资源消耗,如数据库连接、http客户端等。
创建http客户端池:
pool := tobjectpool<thttpclient>.create(5, 5000, procedure(var ainstance: thttpclient)
begin
ainstance := thttpclient.create;
ainstance.useragent := 'myagent';
end);
从池中获取对象:
httpcli := pool.get.item;
statuscode := httpcli.get('https://www.mydomain.com').statuscode;
quick.collections:
定义了具有linq支持的接口list和objectlist。
- txlist
<t>/ ilist<t>:允许使用linq进行正则表达式搜索/删除/更新的接口list。
myarray := ['joe', 'mat', 'lee'];
// 搜索正则表达式匹配项
cout('search for regex match', ccyellow);
for name in myarray.where('e$', true).select do
begin
cout('user %s ends with "e"', [name], etinfo);
end;
- txobjectlist
<t>/ iobjectlist<t>:允许使用linq谓词或表达式进行搜索/删除/更新的接口objectlist。
表达式搜索:
user := listobj.where('profile.name = ?', ['lee']).selectfirst;
对项数组的表达式搜索:
users := listobj.where('roles contains ?', ['superadmin']).select;
谓词搜索:
user := listobj.where(function(auser: tuser): boolean
begin
result := auser.name.startswith('j');
end).selectfirst;
if user <> nil then cout('%s starts with j letter', [user.name], etinfo);
查看quick.linq部分以查看更多允许的函数。
quick.template:
使用字典或委托函数进行字符串模板替换。您可以指定引号的标记字符。
通过传递字典进行替换:
dict := tdictionary<string, string>.create;
dict.add('user', 'john');
dict.add('age', '20');
dict.add('surname', 'peterson');
mytemplate := 'user {{user}} {{surname}} are {{age}} years old.';
template := tstringtemplate.create('{{', '}}', dict);
result := template.replace(mytemplate);
使用委托函数进行替换:
mytemplate := 'user {{user}} {{surname}} are {{age}} years old.';
template := tstringtemplate.create('{{', '}}', function(const atoken: string): string
begin
if atoken = 'user' then result := 'john'
else if atoken = 'surname' then result := 'peterson'
else if atoken = 'age' then result := '20';
end);
result := template.replace(mytemplate);
quick.debug.utils:
调试工具,用于检查性能并获取进入和退出方法的检查点。通过debug编译器指令定义,仅在应用程序以调试模式编译时激活。
在控制台应用程序中,默认使用控制台输出。您可以传递一个记录器以输出到:
tdebugutils.setlogger(ilogger);
跟踪代码的一部分:
function tcalculator.subs(a, b: int64): int64;
begin
{$ifdef debug}
tdebugger.trace(self, format('substract %d - %d', [a, b]));
{$endif}
result := a - b;
// 模拟工作200毫秒
sleep(200);
end;
// 返回:
// 29-06-2020 23:31:41.391 [trace] tcalculator -> substract 30 - 12
计算从点到退出函数的处理时间:
function tcalculator.sum(a, b: int64): int64;
begin
{$ifdef debug}
tdebugger.timeit(self, 'sum', format('sum %d + %d', [a, b]));
{$endif}
result := a + b;
// 模拟工作1秒
sleep(1000);
end;
// 返回:
// 29-06-2020 22:58:45.808 [chrono] tcalculator.sum -> sum 100 + 50 = 1,00s
计算从点到点以及退出函数的处理时间:
function tcalculator.divide(a, b: int64): double;
begin
{$ifdef debug}
var crono := tdebugger.timeit(self, 'divide', format('divide %d / %d', [a, b]));
{$endif}
result := a / b;
// 模拟工作500毫秒
sleep(500);
{$ifdef debug}
crono.breakpoint('only divide');
{$endif}
// 模拟工作1秒
sleep(1000);
{$ifdef debug}
crono.breakpoint('only sleep');
{$endif}
end;
// 返回:
// 29-06-2020 23:25:46.223 [chrono] tcalculator.divide -> first point = 500,18ms
// 29-06-2020 23:25:47.224 [chrono] tcalculator.divide -> second point = 1,00s
// 29-06-2020 23:25:47.225 [chrono] tcalculator.divide -> divide 10 / 2 = 1,50s
当进入和退出函数时获取通知,并计算时间:
function tcalculator.mult(a, b: int64): int64;
begin
{$ifdef debug}
tdebugger.enter(self, 'mult').timeit;
{$endif}
result := a * b;
// 模拟工作2秒
sleep(2000);
end;
// 返回:
// 29-06-2020 22:58:45.808 [enter] >> tcalculator.mult
// 29-06-2020 22:58:47.810 [exit] >> tcalculator.mult in 2,00s
quick.parameters:
使用命令行扩展,可以轻松处理命令行参数。
定义一个从tparameters或tserviceparameters(如果使用quickappservices)继承的类,将可能的参数作为已发布的属性:
uses
quick.parameters;
type
tcommand = (copy, move, remove);
tmymode = (mdadd, mdselect, mdremove);
[commanddescription('使用quick.parameters的简单控制台应用程序示例')]
tmyparameter = class(tparameters)
private
// ... [私有成员]
published
// ... [已发布的属性]
end;
使用参数:
params := tmyparameter.create;
当您使用--help调用exe时,将获得文档。如果需要检查开关或值,可以这样做:
if params.port = 0 then ... if params.silent then ...
quickparameters使用自定义属性来定义特殊的参数条件:
- commanddescription: 定义在帮助文档中描述您的应用程序的文本。
- paramcommand(number): 为单个参数定义命令行中的静态位置。
- paramname(name,alias): 为参数定义不同的名称。允许使用类属性中不允许的特殊字符(如文件名或config.file)。可选的alias参数定义了替代(通常是短名称)参数名称。
- paramhelp(helptext,valuename): 在用法部分定义命令行帮助文本和值名称。
- paramswitchchar(sign): 定义指示开关或参数的字符串或字符。如果没有定义,将默认使用双破折号(--)。
- paramvalueseparator(sign): 定义从值(filename=config.json)中分离参数名称的字符串或字符。如果没有定义,将默认使用等号(=)。
- paramvalueisnextparam: 定义没有值分隔符的参数值(filename c:\config.ini)。
- paramrequired: 定义参数为必需。如果未找到参数,将引发异常。
quickparameter会自动检查值类型。如果将参数值定义为integer,并传递了字母数字值,将引发异常。
帮助定制:
您可以使用colorizehelp定义自己的颜色定制。如果enabled属性为true,则使用自定义颜色,否则使用黑白颜色。
parameters.colorizehelp.enabled := true; parameters.colorizehelp.commandname := cccyan; parameters.colorizehelp.commandusage := ccblue;
当参数检测到帮助参数时,将显示帮助文档。
parameters.showhelp: 显示自动生成的帮助文档。
quick.url.utils:
- getprotocol: 从url中获取协议。
- gethost: 从url中获取主机名。
- getpath: 从url中获取路径。
- getquery: 从url中获取查询部分。
- removeprotocol: 从url中移除协议。
- removequery: 从url中移除查询部分。
- encodeurl: 对url中的路径和查询部分进行编码。
quick.regex.utils:
常用验证工具。
(此部分未给出具体示例代码)
quick.conditions:
以流畅风格进行前置条件和后置条件的验证。
condition.requires在执行某些操作之前评估变量的条件。
condition.ensures在执行某些操作之后评估变量结果的条件。
condition.requires(num, "num")
.isinrange(1, 10, 'value for num is out of range'); // 如果不在范围内,则抛出自定义错误
.isnotgreater(50); // 如果不等于50,则抛出argumentexception
condition.requires(myobj, "myobj")
.withexceptiononfailure(emyexception) // 如果失败,则抛出特定异常
.isnotnull(); // 如果为null,则抛出argumentnullexception
.evaluate(myobj.id > 10); // myobj.id必须大于10
condition.requires(text, "text")
.isnotempty(); // 如果为空,则抛出argumentnullexception
.startswith("<html>") // 如果不以<html>开头,则抛出argumentexception
.endswith("</html>") // 如果不以</html>结尾,则抛出argumentexception
.isnotlowercase; // 如果不是小写,则抛出argumentexception
.evaluate(text.contains("sometxt") or text.contains('othertxt')); // 如果不满足条件,则抛出argumentexception
你想学习delphi或提高你的技能吗?访问 learndelphi.org
发表评论