
QuickLib es una biblioteca Delphi/Firemonkey (Windows, Linux, Android, OSX e iOS) e FPC (Windows & Linux) que contiene funciones interesantes y rápidas para implementar, creada para simplificar el desarrollo de aplicaciones y el soporte de la plataforma cruzada y mejorar la productividad. Delphi Xe8 - Delphi 12 Atenas apoyó.
¡Por favor "establezca" este proyecto en Github! No cuesta nada pero ayuda a hacer referencia al código. 
Si encuentra útil este proyecto, considere hacer una donación.
Áreas de funcionalidad:
Unidades principales Descripción:
Actualizaciones:
Permita que una aplicación de consola se ejecute como modo de consola o modo de servicio con el mismo código que simplifica las tareas de depuración.
if not AppService.IsRunningAsService then
begin
...your code running as console
end
else
begin
AppService.ServiceName := ' MyService ' ;
AppService.DisplayName := ' MyServicesvc ' ;
// you can pass an anonymous method to events
AppService.OnStart := procedure
begin
...your start code
end ;
AppService.OnExecute := YourExecuteFunction;
AppService.OnStop := YourStopFunction;
AppService.CheckParams;
end ;Simplifica la iteración de blob con Azure y Amazon Cloud Storage.
// connect to a Azure blobstorage
QuickAzure := TQuickAzure.Create(AzureAccountName,AzureAccountKey);
// download a blob file to a stream
done := QuickAzure.GetBlob( ' MyContainer ' , ' MyFile.jpg ' ,ResponseInfo,MyStream);
// check if exists a folder
found := ExistFolder( ' MyContainer ' , ' /Public/Documents/Personal ' );
// list blobs starting with a pattern (recursively or not)
for azBlob in ListBlobs( ' MyContainer ' , ' /Public/Documents ' ,Recursive,ResponseInfo) do
begin
if azBlob.Size > 1000 then Showmessage(azBlob. Name );
end ;Funciones de rango CIDR e IP.
// convert ip string to integer
IPv4ToInt( ' 192.168.1.10 ' );
// get first and last ip of a subnet scope
GetIpRange( ' 192.168.100.0 ' , ' 255.255.255.0 ' ,LowIp,HighIP);Las funciones con frecuencia se necesitan en el día de un desarrollador.
// coverts UTC time TDateTime to Local date time
UTCToLocalTime(MyUTCTime);
// generate a 10 char length random password with alfanumeric and signs.
RandomPassword( 10 ,[pfIncludeNumbers,pfIncludeSigns]);
// Capitalize every word of a phrase
CapitalizeAll( ' the grey fox ' ); // returns "The Grey Fox"
// Simple TCounter and TTimeCounter for loops
counter := TCounter;
counter.Init( 200 );
timecounter : TTimeCounter;
timecounter.Init( 10000 );
while true do
begin
Inc(n);
{ your procedural process here }
// every 200 steps writes to console
if counter.Check then writeln(Format( ' Processed %d entries ' ,[n]));
// every 10 seconds writes to console
if timecounter.Check then writeln( ' Im working... ' );
end ;Cronómetro y margen de referencia Un pedazo de código es simple.
// get elapsed time execution of a code part
Chrono := TChronometer.Create(False);
Chrono.Start;
...code you need benchmark
Chrono.Stop;
// shows elapsed time in LongTime format (2 hour(s) and 10 minute(s))
Showmessage(Chrono.TimeElapsed(True));
// shows elapsed time in ShortTime format (02:10:00)
Showmessage(Chrono.TimeElapsed(False));
// get benchmak info of a process
Chrono := TChronoBenchMark.Create;
Chrono.TotalProcess := 100000 ;
for i := 1 to 10000 do
begin
{ your process here }
Chrono.CurrentProcess := i;
// shows estimated time your process will take in x hour(s), x minute(s) x second(s) format
writeln(Chrono.EstimatedTime(True));
// shows speed: num items per second processed of your process
writeln(Format( ' Items processed %d/sec ' ,[Chrono.Speed]));
end ;
writeln(Chrono.ElapsedTime(False)); // shows total time elapsed in 00:00:00 format Escriba mensajes de registro para consolar con colores y más ...
// define which level of output needed
Console.Verbose := LOG_DEBUG;
// writes line to console in red color
cout( ' Error x ' ,etError);
// writes formatted line in green color
coutFmt( ' Proccess %s finished ' ,[ProccesName],etSuccess);
// writes integer
cout( 12348 );
// Connect a QuickLog and write to disk and screen with one line of code (with independent verbose levels)
MyQuickLog := TQuickLog.Create;
MyQuickLog.Verbose := LOG_ALL;
Console.Verbose := LOG_ONLYERRORS;
Console.Log := MyQuickLog;Registre el disco o la memoria con niveles detallados y la rotación de espacio diario o máximo.
// write a header on start with info as running path, appname, debugmode, user, etc...
Log.ShowHeader := True;
// sets log with rotation at 20MB
Log.SetLog( ' .mylog.log ' ,False, 20 );
// write an error message
Log.Add( ' Error x ' ,etError);
// write formatted error message
Log.Add( ' Error is %s ' ,[ErrorStr],etError);Cargue/guarde una configuración como archivo JSON o YAML o teclas de registro de Windows. Cree una clase Descend desde TAPPCONFIGJSON, TAPPCONFIGYAML o TAPPCONFIGREGISTRISTRIMIS y agregadas las propiedades publicadas se cargarán/guardarán. Las configuraciones de archivos se pueden volver a cargar en los cambios de detección de archivos.
// create a class heritage
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 ;
// create your config to json file
// Add Quick.Config.Json to your uses
MyConfig := TMyConfig.Create( ' Config.json ' );
MyConfig.Provider.CreateIfNotExists := True;
MyConfig.Provider.ReloadIfFileModified := True;
MyConfig. Name := ' John ' ;
MyConfig.Surname := ' Smith ' ;
// load
MyConfig.Load;
// save
MyConfig.Save;
// create your config to Windows Registry
// Add Quick.Config.Registry to your uses
MyConfig := TMyConfig.Create;
// Define Registry as HKEY_CURRENT_USERSoftwareMyApp
MyConfig.HRoot := HKEY_CURRENT_USER;
MyConfig.MainKey := ' MyApp ' ;
MyConfig. Name := ' John ' ;
MyConfig.Surname := ' Smith ' ;
// load
MyConfig.Load;
// save
MyConfig.Save;
// Create a custom Config with no default provider
TMyConfig = class (TAppConfig)
...your properties
end ;
MyConfig := TMyConfig.Create(TAppConfigJsonProvider.Create( ' .config.json ' );
Monitorea un archivo para los cambios y lanza eventos.
FileMonitor.Filename := ' .myfile.txt ' ;
// check file changes every 2 seconds
FileMonitor.Interval := 2000 ;
// watch for deleted or modified file events
FileMonitor.Notifies := [mnFileModified, mnFileDeleted)];
FileMonitor.OnFileChange := MyFileChangeFunction;
FileMonitor.Enabled := True;Utiliza para trabajar con objetos JSON.
// When unit declared in uses, a TObject Helper allows all your objects to be loaded or saved to/from json string
MyObject.FromJson := jsonstring;
MyString := MyObject.ToJson;
// You can clone simple objects with clone function
MyObject1.Clone(MyObject2);Enviar correo electrónico con dos líneas de código.
// Send email
SMTP := TSMTP.Create( ' mail.domain.com ' , 25 ,False);
SMTP.SendMail( ' [email protected] ' , ' [email protected] ' , ' Email subject ' , ' My message body ' );
// You can define more advanced options
SMTP.SenderName := ' John ' ;
SMTP.From := ' [email protected] ' ;
SMTP.Recipient := ' [email protected],[email protected] ' ;
SMTP.Subject := ' Email subject ' ;
SMTP.AddBodyFromFile := ' .body.html ' ;
SMTP.CC := ' [email protected] ' ;
SMTP.BCC := ' [email protected] ' ;
SMTP.Attachments.Add( ' .notes.txt ' );
SMTP.SendMail;Clases seguras de hilo.
TthreadedqueueCs: versión de tthreadedqueue con sección crítica.
TthreadObjectList: Lista de objetos seguros de hilo.
Tthreadedqueuelist: lista de colas seguras de hilo. AutoGROW y con sección crítica.
TanonyMoUsThread: crea hilo anónimo que define los métodos de ejecución y terminado. Use los métodos Execute_Sync y OnterMinate_Sync si el código necesita actualizar la interfaz de usuario.
// simple anonymousthread
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;TUNTASK: inicie un hilo de tareas individuales autofree con políticas de control de fallas y reintentos. Los parámetros se pueden pasar y crear en código.
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;TBACKGROWNASTS: Lanza las tareas en segundo plano que permiten el número de trabajadores concurrentes con políticas de control de fallas y reintentos. Use los métodos addTask_Sync y OnterMinate_Sync si el código necesita actualizar la interfaz de usuario.
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: Alternativa al temporizador. Puede asignar tareas con la hora de inicio, repetir opciones y la fecha de vencimiento y el fracaso y volver a intentar las políticas de control. Use addTask_Sync, onterMinate_sync y Onexpired_sync si el código necesita actualizar la interfaz de usuario. Puede asignar métodos anónimos para ejecutar, excepción, terminar y vencer eventos.
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;Gestiona las políticas de fracaso y reintento, definiendo reintentos máximos, tiempo de espera entre reintentos y mecanismo de interrupción del circuito.
Administra los procesos de Windows.
// kill explorer process
KillProcess( ' explorer.exe ' );
// determine if an application is running
if IsProcessRunning( ' explorer.exe ' ) then Showmessage( ' Explorer is running! ' );
// get username who is running an exe
writeln( ' Explorer.exe open by: ' + GetProcessUser( ' explorer.exe ' );
// gets handle of a window with a 20 seconds timeout
if FindWindowTimeout( ' MainWindow ' , 20 ) then writeln( ' Window detected ' );Administra los servicios de Windows.
// detect if a service is installed
if not ServiceIsPresent( ' localhost ' , ' MySvc ' ) then raise Exception.Create( ' Service not installed! ' );
// Start a service
ServiceStart( ' localhost ' , ' MySvc ' );
// Uninstall a service
ServiceUninstall( ' MySvc ' );Formato de cadena.
// Format bytes to MB, GB, TB...
FormatBytes( 50000 ) // shows 50KB
FormatBytes( 90000000 ) // shows 90MB Serializa un objeto de/to json text. Puede definir si se procesará público o publicado (solo Delphi, FPC RTTI solo admite propiedades publicadas)
json := ' {"name":"Peter","age":30} ' ;
serializer := TJsonSerializer.Create(TSerializeLevel.slPublishedProperty);
try
serializer.JsonToObject(user,json);
finally
serializer.Free;
end ;Mapa de campos de una clase a otra. Permite que las asignaciones personalizadas coincidan con diferentes campos y el procedimiento de mapeo personalizado para lanzar/convertir campos manualmente.
// Map values from User1 to User2
TMapper<TUser2>.Map(User);
// Map custom mappings
AutoMapper := TAutoMapper<TUser,TUser2>.Create;
// option1: you can define auto map different named properties
AutoMapper.CustomMapping.AddMap( ' Cash ' , ' Money ' );
AutoMapper.CustomMapping.AddMap( ' Id ' , ' IdUser ' );
// option2: you can decide to modify each property manually or allow to auto someones
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 ;
// option3: you can modify some properties after automapping done
AutoMapper.OnAfterMapping := procedure( const aSrcObj : TUser; aTgtObj : TUser2)
begin
aTgtObj.Money := aSrcObj.Cash * 2 ;
aTgtObj.IdUser := aSrcObj.Id;
end ;
User2 := AutoMapper.Map(User);Utilizado como clase DTO, con funciones JSON Serialize y Mapping incluidas.
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;
// show as json string
Writeln(user.ToJson);
// mapping to other class
user.Mapto(User2);
Writeln(user2.ToJson);
// load from file
user.LoadFromFile( ' .user.json ' );
// save to file
user2.SaveToFile( ' .user2.json ' );
end ;Listas mejoradas con funciones de indexación o búsqueda.
var
users : TIndexedObjectList<TUser>;
begin
users := TIndexedObjectList<TUser>.Create(True);
// create index by property "Name"
users.Indexes.Add( ' Name ' , ' Name ' ,TClassField.cfProperty);
// create index by private field "Id"
users.Indexes.Add( ' Id ' , ' fId ' ,TClassField.cfField);
// get user by "Name" index
writeln(users.Get( ' Name ' , ' Peter ' ).SurName);
end ;FlexValue almacena cualquier tipo de datos y permita pasar a otra clase con operadores integrados y autofrees.
var
value : TFlexValue;
str : string;
num : Integer;
begin
value := ' hello ' ;
str := value ;
value := 123 ;
num := value ;
end ;Matrices mejoradas.
TXARRAY: Matriz con métodos como TList.
var
users : TXArray<TUser>;
begin
users.Add(User);
if users.Count:= TIndexedObjectList<TUser>.Create(True);
// create index by property "Name"
users.Indexes.Add( ' Name ' , ' Name ' ,TClassField.cfProperty);
// create index by private field "Id"
users.Indexes.Add( ' Id ' , ' fId ' ,TClassField.cfField);
// get user by "Name" index
writeln(users.Get( ' Name ' , ' Peter ' ).SurName);
end ;TflexArray: matriz con métodos como tlist que puede almacenar diferentes tipos de valor en la misma matriz.
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 ;TflexPaireRray: matriz con métodos como tlist que puede almacenar diferentes tipos de valor en la misma matriz, y buscar por nombre del elemento.
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 ;Estructura de objeto Yaml.
Tyamlobject: un objeto Yaml es y una matriz de pares de YamlValue.
// create Yaml object from yaml text
yamlobj.ParseYamlValue(aYaml)
// add a pair
yamlobj.AddPair( ' Name ' , ' Mike ' );
// display as yaml structure
Writeln(yamlobj.ToYaml);TyamLarray: matriz de objetos o escalares.
yamlarray.AddElement(TYamlPair.Create( ' Age ' , 30 ));
yamlobj.AddPair( ' myarray ' ,yamlarray);Tyamlpair: par de valores de nombre. El valor puede ser objeto, matriz o escalar.
n := yamlobj.GetPair( ' Name ' ). Value as TYamlInteger;Serializar/deserializar objeto de/a yaml.
// Serialize
text := YamlSerializer.ObjectToYaml(obj);
// Deserialize
YamlSerializer.YamlToObject(obj,yamltext);Evaluar las propiedades del objeto o los valores únicos utilizando expresiones.
if TExpressionParser.Validate(user,( ' (Age > 30) AND (Dept.Name = "Financial") ' ) then
begin
// do something
end ;
if TExpressionParser.Validate(user,( ' (20 > 30) OR (5 > 3) ' ) then
begin
// do something
end ;Hace consultas de Linq a cualquier TobjectList, Tlist, Tarray y TxArray, realizando seleccionado por complejo donde, como la sintaxis SQL, la actualización y el ordenar en su lista. Donde las cláusulas usan espacios de nombres para determinar las propiedades anidadas. Linq puede buscar un elemento en una matriz de propiedades. Ahora incluye y Tarray Helper para agregar, eliminar y buscar con expresiones regulares en una matriz.
// Select multi conditional
for user in TLinq<TUser>.From(userslist).Where( ' (Name = ?) OR (SurName = ?) OR (SurName = ?) ' ,[ ' Peter ' , ' Smith ' , ' Huan ' ]).Select do
begin
// do something
end ;
// Select like and update field
TLinq<TUser>.From(userlist).Where( ' SurName Like ? ' ,[ ' %son ' ]).SelectFirst. Name := ' Robert ' ;
// Select top and Order by field
for user in TLinq<TUser>.From(userlist).Where( ' Age > ? ' ,[ 18 ]).SelectTop( 10 ).OrderBy( ' Name ' ) do
begin
// do something
end ;
// update fields by conditional
TLinq<TUser>.From(userlist).Where( ' Name = ? ' ,[ ' Peter ' ]).Update([ ' Name ' ],[ ' Joe ' ]);
// count results
numusers := TLinq<TUser>.From(userlist).Where( ' (Age > ?) AND (Age < ?) ' ,[ 30 , 40 ]).Count;TCustOMHTTPServer es un simple httpserver intercatado con implementaciones HTTPRequest e HTTPResponse propias para permitir cambios fáciles del motor httpserver. Puede habilitar las páginas de error personalizadas para devolver páginas personalizadas y páginas de errores dinámicos. Thttpserver es la implementación de IndyhttPserver, pero puede definir la suya.
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 ;Cachica objetos o cadenas con un tiempo de vencimiento, para evitar generar esta información cada vez que se necesita (consultas de bases de datos, información difícil de calcular la información, etc.). TMemoryCache permite almacenar en caché de objetos y cadenas. Versión genérica TMemoryCache permite almacenar en caché solo un tipo definido.
// create MemoryCache with 10 seconds purge interval
cache := TMemoryCache.Create( 10 );
// create MemoryCache for a type
cache := TMemoryCache<TMyObj>.Create; // set string to cache without expiration
cache.SetValue( ' mystring ' , ' hello world ' );
// set string to cache with expiration to 10 seconds
cache.SetValue( ' mystring ' , ' this cache will expire in 10 seconds ' ;
// set object to cache
cache.SetValue( ' Obj1 ' ,valueobj); // get string query result
cache.GetValue( ' Query12 ' );
// get integer
cache.TryGetValue<Integer>( ' number ' ,valueint);
// get object
cache.TryGetValue( ' Obj1 ' ,valueobj);EliminarValue: elimina un objeto de la caché.
Proveedores de motor de caché:
TCacheserializerJson: utiliza JSON para serializar los datos de caché.
Tcachecompressorgzip: utiliza GZIP para comprimir los datos de caché.
Tcachecompressorlzo: usa LZO para comprimir los datos de caché.
// create MemoryCache with 20 seconds purge interval and compression with LZO engine
cache := TMemoryCache.Create( 10 , nil ,TCacheCompressorLZO.Create);La inversión del gerente de control permite el autocreate interfacido o el objeto instancionado o autoinyectarlos en las clases de constructor, para evitar la dependencia.
Cree un contenedor para administrar la inyección de dependencia.
iocContainer := TIocContainer.Create;Tipos de registro:
Debe registrar los tipos antes de poder inyectarlos. Un tipo se puede registrar como singleton, transitorio. Singleton : el ciclo de vida será una sola instancia para todas las inyecciones, similar a una variable global. Transitorio : el ciclo de vida será una instancia por cada inyección. Registre un tipo de interfaz en contenedor como transitorio:
iocContainer.RegisterType<IMultService,TMultService>.AsTransient;Registre un tipo de interfaz como singleton, delegando la construcción:
iocContainer.RegisterType<ISumService,TSumService>.AsSingleTon.DelegateTo(
function : TSumService
begin
Result := TSumService.Create;
end
);Instancias de registro:
Registre un objeto de instancia con nombre como transitorio, delegando la construcción:
iocContainer.RegisterInstance<TDivideService>( ' one ' ).AsTransient.DelegateTo(
function : TDivideService
begin
Result := TDivideService.Create(True);
end
);Opciones de registro:
Registre IOPTIONS (solo Singleton):
iocContainer.RegisterOptions<TMyOptions>(MyOptions);Tipos de resolución:
AbtractFactory: crea una clase que intenta resolver todo el parámetro del método de creación con inyección de dependencia.
MyClass := iocContainer.AbstractFactory<TMyBaseClass>(TMyClass);Resolver una dependencia de la interfaz:
multservice := iocContainer.Resolve<IMultService>;
result := multservice.Mult( 2 , 4 );Resolver instancias:
Resolver una dependencia de instancia con nombre:
divideservice := iocContainer.Resolve<TDivideService>( ' other ' );
result := divideservice.Divide( 100 , 2 );Las instancias de la interfaz se liberarán automáticamente, pero las dependencias de instancias solo se liberarán si se definirán como singleton, las instancias transitorias serán destruidas por código.
Defina secciones como clases y guarda como configuración de archivo único. Funciona de manera similar a las opciones de Dotnet. El archivo de opciones puede estar en formato JSON o YAML.
Defina su clase de opción heredada de topos y todas las propiedades publicadas se cargarán/guardarán. Crear contenedor de opciones, con JSonserializer y recarga en el cambio:
Options := TOptionsContainer.Create( ' .options.conf ' ,TJsonOptionsSerializer.Create,True);Agregue una sección a sus opciones de contenedor:
Options.AddSection<TLoggingOptions>( ' Logging ' )Configurar opciones:
Puede definir el nombre de la sección para guardar en el archivo y delegar la configuración de la configuración predeterminada y validar valores:
Options.AddSection<TLoggingOptions>( ' Logging ' ).ConfigureOptions(
procedure(aOptions : TLoggingOptions)
begin
aOptions.Path := ' C: ' ;
end
).ValidateOptions;Validar opciones:
Validate Opciones permite verificar si la configuración de opción se establece entre rangos definidos. Esta validación necesita atributos personalizados previamente asignados a las propiedades en su clase de tutions.
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 ;Use opciones: para recuperar la sección de opciones:
LoggingOptions := Options.GetSection<TLoggingOptions>;
LoggginOptions.Path := ' C:Path ' ;Usar Ioptions: IOPTIONS es una interfaz inyectable de dependencia para los tipos. Puede registrarse con Ioctainer. Registros para hacer inyectables en los métodos de constructor.
UIOptions := Options.GetSectionInterface<TUIOptions>. Value ;
UIOptions.WindowColor := clBlue;Opciones de carga/guardado:
Cargar opciones desde la configuración del archivo:
options.Load;Guardar opciones a la configuración del archivo:
options.Save;Si definió la creación de contenedores con el parámetro ReloadonChanged a True, cada vez que se cambia la configuración del archivo, la configuración se volverá a cargar. Si necesita controlar cuándo recargar, puede escuchar el evento:
Options.OnFileModified := procedure
begin
cout('Detected config file modification!',etWarning);
end;
Definir un conjunto de conexión, subprocesos o cualquier objeto que desee controlar para evitar el consumidor de recursos, como conexiones de bases de datos, clientes HTTP, etc.
Crear grupo de clientes HTTP:
pool := TObjectPool<THTTPClient>.Create( 5 , 5000 ,procedure( var aInstance : THTTPClient)
begin
aInstance := THTTPClient.Create;
aInstante.UserAgent := ' MyAgent ' ;
end );Obtenga objeto de la piscina:
httpcli := pool.Get.Item;
statuscode := httpcli.Get( ' https://www.mydomain.com ' ).StatusCode;Define la lista interna y la lista de objetos con soporte LINQ heredado.
myarray := [ ' Joe ' , ' Mat ' , ' Lee ' ];
// search for regex match
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 ;user := ListObj.Where( ' Profile.Name = ? ' ,[ ' Lee ' ]).SelectFirst;Expresión de búsqueda de elementos:
users := ListObj.Where( ' Roles CONTAINS ? ' ,[ ' SuperAdmin ' ]).Select;Búsqueda de predicado:
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);Consulte la sección Quick.Linq para ver más funciones permitidas.
Plantilla de cadena Reemplazo utilizando una función de diccionario o delegado. Puede especificar caracteres de token citados.
Reemplace el paso de un diccionario:
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);Reemplace con la función delegada:
mytemplate := ' User {{User}} {{SurName}} are {{Age}} years old. ' ;
template := TStringTemplate.Create( ' {{ ' , ' }} ' ,function( const aToken : string) : string
begin
if token = ' User ' then Result := ' John '
else if token = ' Surname ' then Result := ' Peterson '
else if token = ' Age ' then Result := ' 20 ' ;
end );
Result := template.Replace(mytemplate);Depurar Utils para verificar el rendimiento y obtener el punto de control Intro y Salir del método. Defina con una Directiva de depuración de un compilador para estar solo activo cuando su aplicación se compila en modo de depuración. En la consola, aplicaciones usa la consola fuera de forma predeterminada. Puede pasar un registrador para salir en:
TDebugUtils.SetLogger(ilogger);Rastree una parte de su código:
function TCalculator.Subs (a, b: Int64): Int64;
begin
{ $IFDEF DEBUG }
TDebugger.Trace(Self,Format( ' Substract %d - %d ' ,[a,b]));
{ $ENDIF }
Result := a - b;
// simulate working for 200ms
Sleep( 200 );
end ;
// Returns:
// 29-06-2020 23:31:41.391 [TRACE] TCalculator -> Substract 30 - 12Calcule el tiempo para procesar de la función de punto a salida:
function TCalculator.Sum (a, b: Int64): Int64;
begin
{ $IFDEF DEBUG }
TDebugger.TimeIt(Self, ' Sum ' ,Format( ' Sum %d + %d ' ,[a,b]));
{ $ENDIF }
Result := a + b;
// simulate working for 1 seconds
Sleep( 1000 );
end ;
// Returns:
// 29-06-2020 22:58:45.808 [CHRONO] TCalculator.Sum -> Sum 100 + 50 = 1,00sCalcule el tiempo para procesar de punto a punto y función de salida:
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;
// simulate working for 500ms
Sleep( 500 );
{ $IFDEF DEBUG }
crono.BreakPoint( ' Only divide ' );
{ $ENDIF }
// simulate working for 1 second
Sleep( 1000 );
{ $IFDEF DEBUG }
crono.BreakPoint( ' Only Sleep ' );
{ $ENDIF }
end ;
// Returns:
// 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,50sObtenga una notificación cuando ingrese y salga la función, y lo hace:
function TCalculator.Mult (a, b: Int64): Int64;
begin
{ $IFDEF DEBUG }
TDebugger.Enter(Self, ' Mult ' ).TimeIt;
{ $ENDIF }
Result := a * b;
// simulate working for 2 seconds
Sleep( 2000 );
end ;
// Returns:
// 29-06-2020 22:58:45.808 [ENTER] >> TCalculator.Mult
// 29-06-2020 22:58:47.810 [EXIT] >> TCalculator.Mult in 2,00s Trabajar con parámetros de línea de comandos será fácil utilizando la extensión de línea de comandos. Defina una clase heredada de tparameters o tserviceParameters (si trabaja con QuickAppServices) con sus posibles argumentos como propiedades publicadas:
uses
Quick.Parameters;
type
TCommand = (Copy, Move, Remove);
TMyMode = (mdAdd, mdSelect, mdRemove);
[CommandDescription( ' Simple console application example with Quick.Parameters ' )]
TMyParameter = class (TParameters)
private
fCommand : TCommand;
fHost : string;
fPort : Integer;
fRetries : Integer;
fUseTCP : Boolean;
fConfigFile: string;
fSilent: Boolean;
fMyMode: TMyMode;
fLogErrorsConsole: Boolean;
fLogErrors: Boolean;
fShowReport: Boolean;
published
[ParamCommand( 1 )]
[ParamRequired]
[ParamHelp( ' Command action. ' , ' command-action ' )]
property Command : TCommand read fCommand write fCommand;
[ParamName( ' HostName ' ),ParamRequired]
[ParamHelp( ' Define host to connect. ' , ' host ' )]
property Host : string read fHost write fHost;
[ParamName( ' Port ' , ' p ' )]
[ParamValueIsNextParam]
[ParamHelp( ' Define Port to connect (default 80) ' , ' port ' )]
property Port : Integer read fPort write fPort;
[ParamHelp( ' Number of max retries. ' )]
property Retries : Integer read fRetries write fRetries;
[ParamHelp( ' Path to config. ' , ' path ' )]
[ParamName( ' Config-file ' )]
property ConfigFile : String read fConfigFile write fConfigFile;
[ParamHelp( ' Silent mode. ' )]
property Silent : Boolean read fSilent write fSilent;
[ParamHelp( ' Modes (mdAdd, mdSelect, mdRemove) ' )]
property Mode : TMyMode read fMyMode write fMyMode;
end ;
Utilice Param:
params := TMyParameter.Create;Cuando llame a su exe con --help obtendrá documentación. Si necesita verificar un interruptor o valor, puede hacer esto:
if params.Port = 0 then ...
if params.Silent then ...QuickParameters utiliza atributos personalizados para definir condiciones especiales de parámetros:
CommandDescription: Define el texto para describir su aplicación en documentación de ayuda.
ParamCommand (número): define la posición estática en línea de comandos para parámetros únicos.
ParamName (nombre, alias): defina un nombre diferente para el parámetro. Permite usar caracteres especiales no permitidos para propiedades de clase (como nombre de archivo o config.file). El argumento de alias opcional define un nombre de parámetro alternativo (normalmente nombre corto).
ParamHelp (HelPtext, ValueName): define un texto de ayuda de línea de comandos y nombre de valor en la sección de uso.
ParamSwitchChar (signo): define la cadena o Char para indicar el interruptor o el parámetro. Si no se define, se utilizará un tablero doble (-) de forma predeterminada.
ParamValuueSeParator (signo): define la cadena o Char para separar el nombre del parámetro del valor (FileName = config.json). Si no se define, el signo igual (=) se utilizará de forma predeterminada.
ParamValueIsNextParam: define un parámetro con un valor sin separador de valor (nombre de archivo c: config.ini)
Paramrequired: define un parámetro según sea necesario. Si no se encuentra param, se planteará una excepción.
QuickParameter verifica automáticamente los tipos de valor. Si define un valor de parámetro como entero y pasa un alfanumérico, se planteará una excepción.
Ayuda personalización: puede definir su propia personalización de color con ColorizeHelp. La propiedad habilitada utilizará colores personalizados, de lo contrario, se utilizará b/w.
Parameters.ColorizeHelp.Enabled := True;
Parameters.ColorizeHelp.CommandName := ccCyan;
Parameters.ColorizeHelp.CommandUsage := ccBlue;Cuando los parámetros detectan el parámetro de ayuda, se mostrará documentación de ayuda.
Parámetros.showhelp: muestra documentación de ayuda, generada automáticamente:
Parameters v.1.0
Usage: Parameters <command-action> <--HostName=<host>> [--Port <port>] [--Retries=<value>]
[--Config-file=<path>] [--UseTCP] [--Silent] [--Mode=<value>]
[--ShowReport] [--Help]
Simple console application example with Quick.Parameters
Arguments:
Command Command action.
--HostName Define host to connect.
--Port, -p Define Port to connect (default 80)
--Retries Number of max retries.
--Config-file Path to config.
--UseTCP Use TCP connection if present.
--Silent Silent mode.
--Mode Modes (mdAdd, mdSelect, mdRemove)
--Help, -h Show this documentation
Validaciones comúnmente utilizadas.
Validaciones previas y posteriores a la condición en estilo fluido. Condición. Los previos evalúan una variable para las condiciones antes de hacer algunas operaciones. Condición. Las canciones evalúan un resultado variable para las condiciones después de hacer algunas operaciones.
Condition.Requires(num, " num " )
.IsInRange( 1 , 10 , ' value for num is out of range ' ); // throws custom error if not in range
.IsNotGreater( 50 ); // throws ArgumentException if not equal to 128
Condition.Requires(myobj, " myobj " )
.WithExceptionOnFailure(EMyException) // throws specific exception on failure
.IsNotNull() // throws ArgumentNullException if null
.Evaluate(myobj.id > 10 ); // myobj.id must be greater than 10
Condition.Requires(text, " text " )
.IsNotEmpty() // throws ArgumentNullException if empty
.StartsWith( " <html> " ) // throws ArgumentException if not starts with <html>
.EndsWith( " </html> " ) // throws ArgumentException if not ends with </html>
.IsNotLowerCase // thows ArgumentException if not lowercase
.Evaluate(text.Contains( " sometxt " ) or test.Contains( ' othertxt ' )); // throws ArgumentException if not evaluates¿Quieres aprender Delphi o mejorar tus habilidades? Learndelphi.org