时间:2024-05-13 06:52
人气:
作者:admin
QuickLib是一个快速开发库,它提供了诸如AutoMapper、LinQ、IOC依赖注入、MemoryCache、计划任务、Json和Yml配置、序列化程序等多种功能。这个库特别支持Delphi和Firemonkey的多平台开发,包括Windows、Linux、Android、OSX和IOS。同时,QuickLib也支持freepascal,使得开发人员能够更轻松地构建跨平台应用程序并提高生产力。
功能领域:
主要单元描述:
允许控制台应用程序以控制台模式或服务模式运行相同的代码,从而简化调试任务。
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;
简化了与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;
提供CIDR和IP范围功能。
//将IP字符串转换为整数
IPv4ToInt('192.168.1.10');
//获取子网范围的第一个和最后一个IP
GetIpRange('192.168.100.0', '255.255.255.0', LowIp, HighIP);
开发人员日常工作中经常需要的函数。
//将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;
计时器和代码基准测试很简单。
//获取代码部分执行所消耗的时间
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格式显示总经过时间
将日志消息以不同颜色等写入控制台。
//定义需要的输出级别
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;
记录到磁盘或内存,具有详细的日志等级和每日或最大空间轮换功能。
// 在开始时写入包含运行路径、应用程序名称、调试模式、用户等信息的页眉
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');
监视文件的更改并触发事件。
FileMonitor.Filename := '.\myfile.txt';
// 每2秒检查一次文件更改
FileMonitor.Interval := 2000;
// 监视文件被删除或修改的事件
FileMonitor.Notifies := [mnFileModified, mnFileDeleted)];
FileMonitor.OnFileChange := MyFileChangeFunction;
FileMonitor.Enabled := True;
用于处理json对象的工具。
// 当在uses中声明单元时,TObject Helper允许将所有对象从/加载到json字符串
MyObject.FromJson := jsonstring;
MyString := MyObject.ToJson;// 您可以使用clone函数克隆简单对象
MyObject1.Clone(MyObject2);
用两行代码发送电子邮件。
// 发送电子邮件
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;
线程安全类。
TThreadedQueueCS: 使用临界区的TThreadedQueue版本。
TThreadObjectList: 线程安全的对象列表。
TThreadedQueueList: 线程安全的队列列表。支持自动增长和临界区。
TAnonymousThread: 创建匿名线程,定义非链式的Execute和OnTerminate方法。如果代码需要更新UI,请使用Execute_Sync和OnTerminate_Sync方法。
// 简单的匿名线程
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: 启动一个自动释放的单任务线程,具有故障和重试控制策略。可以在代码中传递和创建参数。
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方法。
<name>]或task.[index]访问。 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方法。
您可以为执行、异常、终止和到期事件分配匿名方法。
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的每个任务事件的接口。
管理失败和重试策略,定义最大重试次数、重试之间的等待时间和熔断机制。
管理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('检测到窗口');
管理Windows服务。
// 检测服务是否已安装
if not ServiceIsPresent('localhost','MySvc') then raise Exception.Create('服务未安装!');
// 启动服务
ServiceStart('localhost','MySvc');
// 卸载服务
ServiceUninstall('MySvc');
字符串格式化。
// 将字节格式化为MB、GB、TB...
FormatBytes(50000) // 显示 50KB
FormatBytes(90000000) // 显示 90MB
将对象序列化为json文本或从json文本反序列化为对象。您可以定义是否处理公开或已发布的属性(仅Delphi,fpc rtti仅支持已发布的属性)。
json := '{"name":"Peter","age":30}';
serializer := TJsonSerializer.Create(TSerializeLevel.slPublishedProperty);
try
serializer.JsonToObject(user,json);
finally
serializer.Free;
end;
将一个类的字段映射到另一个类。允许自定义映射以匹配不同的字段,并允许自定义映射过程以手动转换字段。
// 将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);
用作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;
带有索引或搜索功能的改进列表。
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;
FlexValue可以存储任何数据类型,并允许使用集成操作符和自动释放功能传递给其他类。
var
value : TFlexValue;
str : string;
num : Integer;
begin
value := 'hello';
str := value;
value := 123;
num := value;
end;
改进的数组。
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;
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;
将对象序列化/反序列化为Yaml。
// 序列化
text := YamlSerializer.ObjectToYaml(obj);
// 反序列化
YamlSerializer.YamlToObject(obj, yamltext);
使用表达式评估对象属性或单个值。
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;
对任何 TObjectList<T>、TList<T>、TArray<T>和 TXArray<T>执行Linq查询,通过类似SQL语法的复杂Where子句进行Select、更新和排序列表。Where子句使用命名空间来确定嵌套属性。Linq可以在属性数组中搜索元素。
现在包括一个 TArray<string>助手,用于在数组中添加、删除和通过正则表达式搜索。
// 多条件选择
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;
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;
使用过期时间缓存对象或字符串,以避免每次需要时都生成这些信息(数据库查询、难以计算的信息等)。TMemoryCache允许缓存对象和字符串。泛型版本TMemoryCache <T>仅允许缓存定义的类型。
// 创建具有10秒清除间隔的MemoryCache
cache := TMemoryCache.Create(10);
// 为特定类型创建MemoryCache
cache := TMemoryCache<TMyObj>.Create;
// 将字符串设置到缓存中,没有过期时间
cache.SetValue('mystring', 'hello world');
// 将字符串设置到缓存中,10秒后过期
cache.SetValue('mystring', '这个缓存将在10秒后过期');
// 将对象设置到缓存中
cache.SetValue('Obj1', valueobj);
// 获取字符串查询结果
cache.GetValue('Query12');
// 获取整数
cache.TryGetValue<Integer>('number', valueint);
// 获取对象
cache.TryGetValue('Obj1', valueobj);
// 创建具有20秒清除间隔并使用LZO引擎压缩的MemoryCache
cache := TMemoryCache.Create(10, nil, TCacheCompressorLZO.Create);
控制反转管理器允许自动创建接口或实例化对象,或在构造函数类中自动注入它们,以避免依赖关系。
创建一个容器来管理依赖注入。
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
您可以将部分定义为类,并将其保存为单个文件设置。其工作方式类似于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类中的属性上分配自定义属性。
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;
定义连接池、线程池或您想要控制的任何对象池,以避免资源消耗,如数据库连接、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;
定义了具有linQ支持的接口List和ObjectList。
<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;
<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部分以查看更多允许的函数。
使用字典或委托函数进行字符串模板替换。您可以指定引号的标记字符。
通过传递字典进行替换:
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);
调试工具,用于检查性能并获取进入和退出方法的检查点。通过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
使用命令行扩展,可以轻松处理命令行参数。
定义一个从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使用自定义属性来定义特殊的参数条件:
QuickParameter会自动检查值类型。如果将参数值定义为Integer,并传递了字母数字值,将引发异常。
帮助定制:
您可以使用ColorizeHelp定义自己的颜色定制。如果Enabled属性为True,则使用自定义颜色,否则使用黑白颜色。
Parameters.ColorizeHelp.Enabled := True;
Parameters.ColorizeHelp.CommandName := ccCyan;
Parameters.ColorizeHelp.CommandUsage := ccBlue;
当参数检测到帮助参数时,将显示帮助文档。
Parameters.ShowHelp: 显示自动生成的帮助文档。
常用验证工具。
(此部分未给出具体示例代码)
以流畅风格进行前置条件和后置条件的验证。
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
上一篇:没有了
IDE工具RAD Studio 13 Florence重磅发布:64 位