
Última atualização em 31 de agosto de 2022 por Willian Tuttoilmondo
Como aumentar sua produtividade com Class Helpers
Um dos grandes avanços promovidos pelo paradigma de desenvolvimento orientado a objetos, principalmente nos últimos anos, foi a criação de auxiliares que podem ser agregados às classes para efetuar um conjunto específico de ações. A esses auxiliares foi dado um nome um tanto óbvio, mas certeiro: Class Helpers. Estes elementos foram criados para que desenvolvedores pudessem adicionar funcionalidades a uma classe sem precisar estendê-la em uma classe derivada. Isso é extremamente importante, principalmente quando temos desenvolvimentos legados que utilizam, por exemplo, generics e não podemos mudar o tipo base utilizado na implementação mas, mesmo assim, temos que adicionar funcionalidades à uma classe.
Class Helpers não são, extamente, uma novidade. Em outras linguagens, e até mesmo em Delphi, eles já estão por aí há algum tempo mas, como quase ninguém fala deles, muita gente ainda não os conhece. O que veremos aqui é como implementar um Class Helper de maneira a facilitar desenvolvimentos futuros e, assim, ganhar em produtividade e eficiência.
Ah, ao final do artigo você encontrará um link para um pequeno conjunto de Class Helpers desenvolvidos e exibidos aqui.
Antes de começar, vamos às regras
Assim como qualquer implementação, os Class Helpers têm regras a serem seguidas. Não é nada muito extraordinário mas, mesmo assim, elas servem para auxiliar o desenvolvedor a compreender e usar melhor este recurso. Em Delphi, como não poderia deixar de ser, também precisamos nos ater a elas. Sendo assim, aqui estão:
- Class Helpers não podem conter construtores ou destrutores;
- Class Helpers não podem conter campos;
- Class Helpers não podem conter métodos abstratos;
- Class Helpers não podem sobrescrever métodos da classe estendida.
Entendendo estas quatro regras muito simples, precisamos ter em mente que, ao criarmos um Class Helper, este não pode ser referenciado em nenhuma parte do código fonte, a não ser nos seguintes casos:
- Quando declarando a extensão de um Class Helper;
- Ao ser usado em uma chamada (Bit)SizeOf;
- Ao ser usado em uma chamada TypeInfo.
Outra característica à qual precisamos nos ater é o fato de que, independente do número de Class Helpers que tenhamos desenvolvido para uma classe, apenas um pode ser usado por vez. Mesmo que tenhamos criado vários Class Helpers, e declarado todos eles na seção uses, apenas um deles será efetivamente utilizado.
Como isso funciona na prática?
Bem, vamos começar pelo básico. Para usar um Class Helper, antes de tudo, precisamos ter uma classe para efetuar tais “personalizações”. Podemos usar uma classe já existente (como a TStrings, por exemplo) ou criar uma classe novinha em folha. No intuito de manter o artigo o mais didático possível, vamos criar uma classe e, depois, criar um Class Helper para ela. Sendo assim, vamos lá.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | unit Classes.NewClass; interface type TNewClass = class public function Response: Integer; end; implementation function TNewClass.Response: Integer; begin Result := 33; end; end. |
E, com a classe definida, vamos definir nosso Class Helper.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | unit Helpers.NewClass; interface uses Classes.NewClass; type TNewClassHelper = class helper for TNewClass public function NewResponse: Integer; end; implementation function TNewClassHelper.NewResponse: Integer; begin Result := 42; end; end. |
Agora que já temos uma classe e um Class Helper criados, podemos ver como uní-los para que tudo funcione.
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 49 50 51 52 53 54 55 56 57 | unit Singletons.NewClass; interface uses Classes.NewClass; type TNewClassSingleton = class public class function Instance: TNewClass; class function Response: Integer; class function NewResponse: integer; end; implementation uses Helpers.NewClass; var FInstance: TNewClass; function GetInstance: TNewClass begin if not Assigned(FInstance) then begin FInstance := TNewClass.Create; end; Result := FInstance; end; class function TNewClassSingleton.Instance: TNewClass; begin Result := GetInstance; end; class function TNewClassSingleton.Response: Integer; begin Result := GetInstance.Response; end; class function TNewClassSingleton.NewResponse: integer; begin Result := GetInstance.NewResponse; end; initialization finalization if Assigned(FInstance) then begin FInstance.DisposeOf; end; end. |
Aqui podemos ver alguns exemplos de orientação a objetos, alguns que já discutimos antes, como Singleton, por exemplo. Mas, mais importante que isso, podemos perceber que, ao unir uma classe a um Class Helper, podemos facilitar – e muito – o desenvolvimento de funcionalidades sem a necessidade de criar extensões de classes para que elas executem métodos diferentes dos que foram originalmente projetados para ela. Originalmente, a classe possui apenas o método Response mas, ao adicionarmos o Class Helper, o objeto derivado da classe TNewClass também pode executar o método NewResponse. Fácil, não?!
Class Helpers e a ocultação de métodos
Uma característica do uso de Class Helpers é a ocultação de métodos. Lá nas regras eu deixei bem claro que não podemos sobrescrever métodos, mas não disse que não poderíamos ocultá-los. Mas, como assim?!
Vamos supor que tenhamos uma necessidade “obscura” de alterar completamente o processamento em um método qualquer de uma classe. Em uma extensão, criaríamos um método com sobrescrita (override) – desde que removamos a instrução de uso da parte herdada do método (inherited) – ou reintrodução (reintroduce) do método original. Num Class Helper, claro, a coisa é diferente (e mais simples). Vejamos o código de um novo Class Helper para nossa classe TNewClass.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | unit Helpers.NewClass2; interface uses Classes.NewClass; type TNewClassHelper2 = class helper for TNewClass public function Response: Integer; end; implementation function TNewClassHelper2.Response: Integer; begin Result := 42; end; end. |
Sendo assim, ao declararmos o uso do novo Class Helper, o compilador entenderá que o método Response a ser utilizado é o que faz parte do Class Helper e não o original da classe, ou seja, a resposta será 42 (constante no Class Helper) ao invés de 33 (constante na classe).
Ah, e claro que também temos uma regra para isso: o método no Class Helper deve ter a mesma assinatura que o método da classe, ou isso gerará um erro em tempo de compilação. Simples!
E se eu quiser desenvolver mais de um Class Helper para a minha classe?
Você pode, sem problema algum. Lembra que lá nas regras eu disse que “independente do número de Class Helpers que tenhamos desenvolvido para uma classe, apenas um pode ser usado por vez”? Isso significa que, mesmo que eu declare o uso de mais de um Class Helper para minha classe, o compilador entenderá que apenas o último deve ser considerado e eliminará os demais em tempo de compilação.
Vamos desenvolver um terceiro Class Helper para exemplificar como isso funciona.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | unit Helpers.NewClass3; interface uses Classes.NewClass; type TNewClassHelper3 = class helper for TNewClass public function OtherNewResponse: Integer; end; implementation function TNewClassHelper3.OtherNewResponse: Integer; begin Result := 0; end; end. |
Vamos agora adicionar ao nosso Singleton este novo Class Helper.
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | unit Singletons.NewClass; interface uses Classes.NewClass; type TNewClassSingleton = class public class function Instance: TNewClass; class function Response: Integer; class function NewResponse: integer; class function OtherNewResponse: integer; end; implementation uses Helpers.NewClass, Helpers.NewClass3; var FInstance: TNewClass; function GetInstance: TNewClass begin if not Assigned(FInstance) then begin FInstance := TNewClass.Create; end; Result := FInstance; end; class function TNewClassSingleton.Instance: TNewClass; begin Result := GetInstance; end; class function TNewClassSingleton.Response: Integer; begin Result := GetInstance.Response; end; class function TNewClassSingleton.NewResponse: integer; begin Result := GetInstance.NewResponse; // Gerará erro de compilação end; class function TNewClassSingleton.OtherNewResponse: integer; begin Result := GetInstance.OtherNewResponse; end; initialization finalization if Assigned(FInstance) then begin FInstance.DisposeOf; end; end. |
Como disse antes, o compilador Delphi entende que apenas um Class Helper pode ser vinculado à classe a que ele se destina. Sendo assim, apenas o último Class Helper declarado é considerado pelo compilador, sendo os demais descartados. Mas, como somos teimosos e decidimos utilizar um método constante no primeiro Class Helper, isso gerará um erro de compilação, já que o compilador ignora o primeiro Class Helper e, portanto, seu método não pode ser encontrado.
Mas tem alguma utilidade prática pra tudo isso?
Claro! Uma das principais formas de tornar um código Delphi mais limpo, eficiente e produtivo é a utilização de Class Helpers para diminuir o número de instruções que o desenvolvedor necessita para chegar a um determinado resultado. Um dos meus favoritos é um Class Helper que desenvolvi para minhas APIs desenvolvidas em Delphi. Para trabalhar com objetos JSON de maneira mais prática, acabei desenvolvendo Class Helpers que tornam mais simples e intuitiva a sintaxe na hora de decompor e analisar, em tempo de excução, os objetos trocados na comunicação.
Abaixo, seguem os códigos de dois destes Class Helpers:
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | unit Helper.JSONValue; interface uses System.JSON; type TJSONValueHelper = class helper for TJSONValue procedure Clear; function IsJSONObject: Boolean; function IsJSONArray: Boolean; function IsChar: Boolean; function IsString: Boolean; function Length: Integer; function IsInteger: Boolean; function InRange(const AMin, AMax: Integer): Boolean; function IsFloat: Boolean; function InRangeF(const AMin, AMax: Double): Boolean; function IsBoolean: Boolean; function AsJSONArray: TJSONArray; function AsJSONObject: TJSONObject; function AsInteger: Integer; function AsFloat: Double; function AsString: String; function AsBoolean: Boolean; function AsDateTime: TDateTime; function AsUnsignedInt: UInt64; end; implementation uses System.SysUtils, System.DateUtils, Helper.Str; { TJSONValueHelper } function TJSONValueHelper.AsBoolean: Boolean; begin case Self is TJSONNull of True : Result := false; False: begin try Result := Self.GetValue<Boolean>; except Result := False; end; end; end; end; function TJSONValueHelper.AsDateTime: TDateTime; begin try Result := ISO8601ToDate(Self.AsString.Trim); except Result := 0; end; end; function TJSONValueHelper.AsFloat: Double; begin case Self is TJSONNull of True : Result := 0; False: begin try Result := Self.GetValue<Double>; except Result := 0; end; end; end; end; function TJSONValueHelper.AsInteger: Integer; begin case Self is TJSONNull of True : Result := 0; False: begin try Result := Self.GetValue<Integer>; except Result := 0; end; end; end; end; function TJSONValueHelper.AsJSONArray: TJSONArray; begin try Result := Self as TJSONArray; except Result := nil; end; end; function TJSONValueHelper.AsJSONObject: TJSONObject; begin try Result := Self as TJSONObject; except Result := nil; end; end; function TJSONValueHelper.AsString: String; begin try case Self.ToString.Trim.Unquote = 'null' of True : Result := EmptyStr; False: Result := Self.ToString.Trim.Unquote; end; except Result := EmptyStr; end; end; function TJSONValueHelper.AsUnsignedInt: UInt64; begin case Self is TJSONNull of True : Result := 0; False: begin try Result := Self.GetValue<UInt64>; except Result := 0; end; end; end; end; procedure TJSONValueHelper.Clear; begin if Assigned(Self) then begin {$IFNDEF VCL} Self.DisposeOf; {$ELSE} FreeAndNil(Self); {$ENDIF} end; end; function TJSONValueHelper.InRange(const AMin, AMax: Integer): Boolean; begin Result := IsInteger and (Self.AsInteger >= AMin) and (Self.AsInteger <= AMax); end; function TJSONValueHelper.InRangeF(const AMin, AMax: Double): Boolean; begin Result := IsFloat and (Self.AsFloat >= AMin) and (Self.AsFloat <= AMax); end; function TJSONValueHelper.IsBoolean: Boolean; var strValue: string; begin strValue := Self.AsString.ToLower; Result := (strValue = 'true') or (strValue = 'false'); end; function TJSONValueHelper.IsChar: Boolean; begin Result := Self.AsString.Length = 1; end; function TJSONValueHelper.IsFloat: Boolean; var strValue: string; begin strValue := Self.AsString; Result := strValue.Contains('.') and (strValue.Length - strValue.NumbersOnly.Length = 1); end; function TJSONValueHelper.IsInteger: Boolean; begin Result := Self.AsString.IsNumbersOnly; end; function TJSONValueHelper.IsJSONArray: Boolean; begin try Result := Self is TJSONArray; except Result := False; end; end; function TJSONValueHelper.IsJSONObject: Boolean; begin try Result := Self is TJSONObject; except Result := False; end; end; function TJSONValueHelper.IsString: Boolean; begin Result := Self.AsString.LettersOnly.Length > 0; end; function TJSONValueHelper.Length: Integer; begin Result := Self.AsString.Length; 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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | unit Helper.JSONObject; interface uses System.Classes, System.JSON; type TJSONObjectHelper = class helper for TJSONObject strict private function GetNode(const AName: string): TJSONValue; procedure SetNode(const AName: string; const Value: TJSONValue); public function HasProperty(const AProperty: string): Boolean; function IndexOf(const AProperty: string): Integer; procedure Clear; procedure ClearObject; function IsJSONArray(const AProperty: string): Boolean; function IsJSONObject(const AProperty: string): Boolean; function AddStringPair(const Str, Val: string): TJSONObject; function AddIntegerPair(const Str: string; const Val: Integer): TJSONObject; function AddFloatPair(const Str: string; const Val: Extended): TJSONObject; function AddBooleanPair(const Str: string; const Val: Boolean): TJSONObject; function AddDatePair(const Str: string; const Val: TDate): TJSONObject; function AddTimePair(const Str: string; const Val: TTime): TJSONObject; function AddDateTimePair(const Str: string; const Val: TDateTime): TJSONObject; function AddISODatePair(const Str: string; const Val: TDate): TJSONObject; function AddISODateTimePair(const Str: string; const Val: TDateTime): TJSONObject; function AddBinaryPair(const Str: string; const Val: TStream): TJSONObject; function DeleteNode(const ANode: string): Boolean; function PrettyFormat: string; function Minify: string; property Node[const AName: string]: TJSONValue read GetNode write SetNode; end; implementation uses System.SysUtils, Soap.EncdDecd, System.NetEncoding, Helper.Integer, Helper.Str, System.Generics.Collections; { TJSONObjectHelper } function TJSONObjectHelper.AddBinaryPair(const Str: string; const Val: TStream): TJSONObject; begin Result := Self.AddPair(Str, string(EncodeBase64(Val, Val.Size))); end; function TJSONObjectHelper.AddBooleanPair(const Str: string; const Val: Boolean): TJSONObject; begin Result := Self.AddPair(Str, TJSONBool.Create(Val)); end; function TJSONObjectHelper.AddDatePair(const Str: string; const Val: TDate): TJSONObject; begin Result := Self.AddPair(Str, FormatDateTime(FormatSettings.ShortDateFormat, Val)); end; function TJSONObjectHelper.AddDateTimePair(const Str: string; const Val: TDateTime): TJSONObject; begin Result := Self.AddPair(Str, FormatDateTime(FormatSettings.ShortDateFormat + ' HH' + FormatSettings.TimeSeparator + 'NN' + FormatSettings.TimeSeparator + 'SS', Val)); end; function TJSONObjectHelper.AddFloatPair(const Str: string; const Val: Extended): TJSONObject; begin Result := Self.AddPair(Str, TJSONNumber.Create(Val)); end; function TJSONObjectHelper.AddIntegerPair(const Str: string; const Val: Integer): TJSONObject; begin Result := Self.AddPair(Str, TJSONNumber.Create(Val)); end; function TJSONObjectHelper.AddISODatePair(const Str: string; const Val: TDate): TJSONObject; begin Result := Self.AddPair(Str, FormatDateTime('YYYY-MM-DD', Val)); end; function TJSONObjectHelper.AddISODateTimePair(const Str: string; const Val: TDateTime): TJSONObject; begin Result := Self.AddPair(Str, FormatDateTime('YYYY-MM-DD HH:NN:SS', Val)); end; function TJSONObjectHelper.AddStringPair(const Str, Val: string): TJSONObject; begin case Val = EmptyStr of True : Result := Self.AddPair(Str, nil); False: Result := Self.AddPair(Str, Val); end; end; function TJSONObjectHelper.AddTimePair(const Str: string; const Val: TTime): TJSONObject; begin Result := Self.AddPair(Str, FormatDateTime('HH' + FormatSettings.TimeSeparator + 'NN' + FormatSettings.TimeSeparator + 'SS', Val)); end; procedure TJSONObjectHelper.Clear; begin if Assigned(Self) then begin {$IFNDEF VCL} Self.DisposeOf; {$ELSE} FreeAndNil(Self); {$ENDIF} end; end; procedure TJSONObjectHelper.ClearObject; var i: Integer; begin for i := 0 to Pred(Self.Count) do begin Self.Pairs[i].DisposeOf; end; end; function TJSONObjectHelper.DeleteNode(const ANode: string): Boolean; begin Result := Self.HasProperty(ANode); if not Result then begin Exit; end; Self.Pairs[Self.IndexOf(ANode)].DisposeOf; end; function TJSONObjectHelper.GetNode(const AName: string): TJSONValue; begin Result := nil; if not HasProperty(AName) then begin Exit; end; Result := GetValue(AName); end; function TJSONObjectHelper.HasProperty(const AProperty: string): Boolean; var jsonValue: TJSONValue; begin jsonValue := nil; try jsonValue := Self.Values[AProperty]; finally Result := Assigned(jsonValue); end; end; function TJSONObjectHelper.IndexOf(const AProperty: string): Integer; begin for Result := 0 to Count.Pred do begin if Pairs[Result].ToString.Contains(AProperty.Quoted('"')) then begin Exit; end; end; Result := -1; end; function TJSONObjectHelper.IsJSONArray(const AProperty: string): Boolean; begin Result := HasProperty(AProperty) and (Self.GetValue(AProperty) is TJSONArray); end; function TJSONObjectHelper.IsJSONObject(const AProperty: string): Boolean; begin Result := HasProperty(AProperty) and (Self.GetValue(AProperty) is TJSONObject); end; function TJSONObjectHelper.Minify: string; begin Result := Self.ToJSON; end; function TJSONObjectHelper.PrettyFormat: string; begin {$IFDEF VER330} Result := Self.Format; {$ELSE} Result := TJson.Format(Self); {$ENDIF} end; procedure TJSONObjectHelper.SetNode(const AName: string; const Value: TJSONValue); begin if HasProperty(AName) then begin Self.Pairs[Self.IndexOf(AName)].Destroy; end; AddPair(AName, Value); end; end. |
Esses Class Helpers facilitam muito meu código e aumentam muito minha produtividade. Um exemplo é este método que tenho em uma classe que converte um registro do banco de dados em um objeto JSON:
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | function TBasicDBConnection.RecordAsJSON(const ADataSet: TFDQuery): TJSONObject; var i : Integer; stmBlob : TMemoryStream; fmtSettings: TFormatSettings; jsonObject : TJSONObject; function IsJSON(const AStr: string; out AObject: TJSONObject): Boolean; begin AObject := nil; Result := False; if not ((Pos('{', AStr) = 1) and (AStr[Length(AStr)] = '}')) then begin Exit; end; try AObject := TJSONObject.ParseJSONValue(AStr) as TJSONObject; Result := True; except Result := False; end; end; begin Result := TJSONObject.Create; fmtSettings := FormatSettings; FormatSettings.ShortDateFormat := 'yyyy-MM-dd'; FormatSettings.DateSeparator := '-'; FormatSettings.DecimalSeparator := '.'; for i := 0 to Pred(ADataSet.FieldCount) do begin case ADataSet.Fields[i].DataType of // Tipos string ftString , ftFixedChar , ftWideString , ftFixedWideChar, ftWideMemo : begin case IsJSON(ADataSet.Fields[i].AsString, jsonObject) of True : Result.AddPair(ADataSet.Fields[i].FieldName, jsonObject); False: Result.AddStringPair(ADataSet.Fields[i].FieldName, ADataSet.Fields[i].AsString); end; end; // Tipo GUID ftGuid : Result.AddStringPair(ADataSet.Fields[i].FieldName, ADataSet.Fields[i].AsString); // Tipos inteiros ftAutoInc , ftSmallint , ftInteger , ftWord , ftLargeint , ftLongWord , ftShortint , ftByte : Result.AddIntegerPair(ADataSet.Fields[i].FieldName, ADataSet.Fields[i].AsInteger); // Tipo booleano ftBoolean : Result.AddBooleanPair(ADataSet.Fields[i].FieldName, ADataSet.Fields[i].AsBoolean); // Tipos flutuantes ftFloat , ftCurrency , ftBCD , ftFMTBcd , ftExtended , ftSingle : Result.AddFloatPair(ADataSet.Fields[i].FieldName, ADataSet.Fields[i].AsFloat); // Tipos Data/Hora ftDate : Result.AddDatePair(ADataSet.Fields[i].FieldName, ADataSet.Fields[i].AsDateTime); ftTime : Result.AddTimePair(ADataSet.Fields[i].FieldName, ADataSet.Fields[i].AsDateTime); ftDateTime , ftTimeStamp , ftOraTimeStamp : Result.AddDateTimePair(ADataSet.Fields[i].FieldName, ADataSet.Fields[i].AsDateTime); // Tipos BLOB ftBlob , ftMemo , ftFmtMemo , ftOraBlob , ftOraClob : begin stmBlob := TMemoryStream.Create; try TBlobField(ADataSet.Fields[i]).SaveToStream(stmBlob); Result.AddBinaryPair(ADataSet.Fields[i].FieldName, stmBlob); finally stmBlob.Free; end; end; end; end; FormatSettings := fmtSettings; end; |
E existem Class Helpers para tipos primitivos?
Sim, existem, mas eles não se chamam Class Helpers, mas Record Helpers. Em essência, eles são idênticos aos Class Helpers, mas a diferença está no fato que, ao invés de classes, eles estendem tipos como string, integer e extended, por exemplo. Vocês devem ter notado que eu tenho declarado nos meus Class Helpers de para JSON um Record Helper chamado Helper.Str. Como o nome sugere, ele é um helper desenvolvido para simplificar a sintaxe de operações com strings. Mesmo que a própria Embarcadero já tenha desenvolvido um e que eu pudesse utilizá-lo (ele está na unit System.SysUtils), a sintaxe de alguns métodos nunca me agradou. Então, por uma questão pessoal, acabei desenvolvendo este Record Helper e ele se prova muito útil, principalmente quando preciso executar operações encadeadas com strings. Um exemplo pode ser visto no seguinte trecho de código do Class Helper para a classe TJSONValue:
1 2 3 4 5 6 7 8 9 10 11 | function TJSONValueHelper.AsString: String; begin try case Self.ToString.Trim.Unquote = 'null' of True : Result := EmptyStr; False: Result := Self.ToString.Trim.Unquote; end; except Result := EmptyStr; end; end; |
A linha Self.ToString.Trim.Unquote mostra que, além do método interno do Class Helper ToString, que converte o TJSONValue em string, os métodos Trim e Unquote, presentes no Record Helper para tratar strings, são invocados em uma única linha, já que o retorno de cada um deles é a própria string.
E para não deixar ninguém com a sensação de que a informação está incompleta, aqui segue meu Record Helper para o tratamento de strings:
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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 | unit Helper.Str; interface uses System.SysUtils, System.JSON; type TMStringHelper = record helper for string strict private function GetChar(AIndex: Integer): Char; procedure SetChar(AIndex: Integer; const Value: Char); public procedure Clear; procedure CreateGUID; function Concat(const AElements: TArray<string>): string; function Replace(const APatern, ANewValue: string; AFlags: TReplaceFlags): string; function RemoveChar(const AChar: Char): string; function RemoveChars(const AChars: array of Char): string; function CountOccurrences(const AChar: Char): Integer; function IncludeTrailingPathDelimiter: string; function IsEmpty: Boolean; function IsFloat: Boolean; function IsNumbersOnly: Boolean; function IsLettersOnly: Boolean; function IsMD5Hash: Boolean; function IsGUID: Boolean; function IsBoolean: Boolean; function InArray(const AArray: TArray<string>): Boolean; function Equals(const AStr: string): Boolean; function Compare(const AStr: string): Integer; function NumbersOnly: string; function LettersOnly: string; function Contains(const AStr: string): Boolean; overload; function Contains(const AStrs: array of string; const AAny: Boolean = True): Boolean; overload; function Quoted(const AQuoteChar: Char = #39): string; function DoubleQuote: string; function Unquote: string; function Format(const ATerms: array of const): string; function ToLower: string; function ToUpper: string; function ToUTF8: string; function ToAnsi: AnsiString; function Trim: string; function TrimLeft: string; function TrimRight: string; function FirstUpper: string; function LPAD(const ALength: Integer; const AChar: Char): string; function RPAD(const ALength: Integer; const AChar: Char): string; function LeftSpaces(const ANumSpaces: Integer): string; function RightSpaces(const ANumSpaces: Integer): string; function ToInteger(const ADefValue: Integer = 0; const IsHex: Boolean = False): Integer; function ToFloat(const ADefValue: Extended = 0): Extended; function Copy(const AStart, ALength: Integer): string; function Delete(const AStart, ALength: Integer): string; function Length: Integer; function LengthBetween(const ALowerLimit, AHigherLimit: Integer): Boolean; function EscapeQuotes(const AQuote: Char = '"'): string; function ToJSON: TJSONObject; function Split(const ASeparator: Char): TArray<string>; overload; function Split(const ASeparator: string): TArray<string>; overload; function Pos(const ASubStr: string): Integer; function PosEx(const ASubStr: string; const AOffset: Integer): Integer; function Unaccent: string; function ToBase64: string; function DecodeBase64: string; function RemoveEscapes: string; property Char[AIndex: Integer]: Char read GetChar write SetChar; end; implementation uses System.Character, Helper.Integer, System.NetEncoding, System.Classes, System.RegularExpressions, System.StrUtils; { TMStringHelper } function TMStringHelper.Contains(const AStr: string): Boolean; begin Result := System.Pos(AStr, Self) > 0; end; procedure TMStringHelper.Clear; begin Self := EmptyStr; end; function TMStringHelper.Compare(const AStr: string): Integer; begin Result := CompareStr(Self, AStr); end; function TMStringHelper.Concat(const AElements: TArray<string>): string; var i: Integer; begin Result := Self; for i := 0 to Pred(System.Length(AElements)) do begin Result := Result + AElements[i]; end; end; function TMStringHelper.Contains(const AStrs: array of string; const AAny: Boolean): Boolean; var i: Integer; begin Result := False; for i := 0 to System.Length(AStrs) do begin if Self.Contains(AStrs[i]) then begin Continue; end; Result := Contains(AStrs[i]); case AAny of True : begin if Result then begin Exit; end; end; False: begin if not Result then begin Exit; end; end; end; end; end; function TMStringHelper.Copy(const AStart, ALength: Integer): string; begin Result := System.Copy(Self, AStart, ALength); end; function TMStringHelper.CountOccurrences(const AChar: Char): Integer; var i: Integer; begin Result := 0; {$IFDEF ANDROID} for i := 0 to Pred(Length) do {$ELSE} for i := 1 to Length do {$ENDIF} begin if Self[i] = AChar then begin Inc(Result); end; end; end; procedure TMStringHelper.CreateGUID; var guidGUID: TGUID; begin System.SysUtils.CreateGUID(guidGUID); Self := guidGUID.ToString.ToLower.Replace('{', EmptyStr, [rfReplaceAll]).Replace('}', EmptyStr, [rfReplaceAll]); end; function TMStringHelper.DecodeBase64: string; var stmInput : TStringStream; stmOutput: TStringStream; begin Result := EmptyStr; if Self.IsEmpty then begin Exit; end; stmOutput := TStringStream.Create; stmInput := TStringStream.Create(Self); stmOutput.SetSize(stmInput.Size); TNetEncoding.Base64.Decode(stmInput, stmOutput); Result := stmOutput.DataString; stmInput.DisposeOf; stmOutput.DisposeOf; end; function TMStringHelper.Delete(const AStart, ALength: Integer): string; begin System.Delete(Self, AStart, ALength); end; function TMStringHelper.DoubleQuote: string; begin Result := Self.Replace(#39, #39#39, [rfReplaceAll]); end; function TMStringHelper.Equals(const AStr: string): Boolean; begin Result := Self = AStr; end; function TMStringHelper.EscapeQuotes(const AQuote: Char): string; begin Result := StringReplace(Self, AQuote, '\' + AQuote, [rfReplaceAll]); end; function TMStringHelper.FirstUpper: string; var strFirst: string; begin Result := Self.ToLower; strFirst := Result[1]; Result[1] := System.SysUtils.UpperCase(strFirst)[1]; end; function TMStringHelper.Format(const ATerms: array of const): string; begin Result := System.SysUtils.Format(Self, ATerms); end; function TMStringHelper.GetChar(AIndex: Integer): Char; begin Result := Self[AIndex]; end; function TMStringHelper.InArray(const AArray: TArray<string>): Boolean; var strElement: string; begin Result := False; for strElement in AArray do begin Result := Self.Equals(strElement); if Result then begin Break; end; end; end; function TMStringHelper.IncludeTrailingPathDelimiter: string; begin Result := System.SysUtils.IncludeTrailingPathDelimiter(Self); end; function TMStringHelper.IsBoolean: Boolean; begin Result := Self.ToLower.Equals('true') or Self.ToLower.Equals('false'); end; function TMStringHelper.IsEmpty: Boolean; begin Result := Self = EmptyStr; end; function TMStringHelper.IsFloat: Boolean; begin Result := (Self.CountOccurrences(FormatSettings.DecimalSeparator) = 1) and Self.Replace(FormatSettings.DecimalSeparator, EmptyStr, [rfReplaceAll]).IsNumbersOnly; end; function TMStringHelper.IsGUID: Boolean; begin Result := TRegEx.IsMatch(Self, '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}'); end; function TMStringHelper.IsLettersOnly: Boolean; begin Result := TRegEx.IsMatch(Self, '[a-zA-Z]+'); end; function TMStringHelper.IsMD5Hash: Boolean; begin Result := TRegEx.IsMatch(Self, '[a-f0-9]{32}'); end; function TMStringHelper.IsNumbersOnly: Boolean; begin Result := TRegEx.IsMatch(Self, '[0-9]+'); end; function TMStringHelper.LeftSpaces(const ANumSpaces: Integer): string; var i: Integer; begin Result := Self; i := 0; if ANumSpaces < 1 then begin Exit; end; repeat Result := ' ' + Result; i.Inc; until i > ANumSpaces; end; function TMStringHelper.Length: Integer; begin Result := System.Length(Self); end; function TMStringHelper.LengthBetween(const ALowerLimit, AHigherLimit: Integer): Boolean; begin Result := (Self.Length >= ALowerLimit) and (Self.Length <= AHigherLimit); end; function TMStringHelper.LettersOnly: string; var i: Integer; begin Result := EmptyStr; {$IFDEF ANDROID} for i := 0 to Pred(Length) do {$ELSE} for i := 1 to Length do {$ENDIF} begin if Self[i].IsLetter then begin Result := Result + Self[i]; end; end; end; function TMStringHelper.LPAD(const ALength: Integer; const AChar: Char): string; begin Result := Self; while Result.Length.MinorThan(ALength) do begin Result := AChar + Result; end; end; function TMStringHelper.NumbersOnly: string; var i: Integer; begin Result := EmptyStr; {$IFDEF ANDROID} for i := 0 to Pred(Length) do {$ELSE} for i := 1 to Length do {$ENDIF} begin if Self[i].IsNumber then begin Result := Result + Self[i]; end; end; end; function TMStringHelper.Pos(const ASubStr: string): Integer; begin Result := System.Pos(ASubStr, Self); end; function TMStringHelper.PosEx(const ASubStr: string; const AOffset: Integer): Integer; begin Result := System.StrUtils.PosEx(ASubStr, Self, AOffset); end; function TMStringHelper.Quoted(const AQuoteChar: Char): string; begin Result := AQuoteChar + Self + AQuoteChar; end; function TMStringHelper.RemoveChar(const AChar: Char): string; begin Result := Self.Replace(AChar, EmptyStr, [rfReplaceAll]); end; function TMStringHelper.RemoveChars(const AChars: array of Char): string; var i: Integer; begin Result := Self; for i := 0 to System.Length(AChars).Pred do begin Result := Result.RemoveChar(AChars[i]); end; end; function TMStringHelper.RemoveEscapes: string; begin Result := Self.Replace('\/', '/', [rfReplaceAll]).Replace('\"', '"', [rfReplaceAll]).Replace('\r', #13, [rfReplaceAll]).Replace('\n', #10, [rfReplaceAll]); end; function TMStringHelper.Replace(const APatern, ANewValue: string; AFlags: TReplaceFlags): string; begin Result := StringReplace(Self, APatern, ANewValue, AFlags); end; function TMStringHelper.RightSpaces(const ANumSpaces: Integer): string; var i: Integer; begin Result := Self; i := 0; if ANumSpaces < 1 then begin Exit; end; repeat Result := Result + ' '; i.Inc; until i > ANumSpaces; end; function TMStringHelper.RPAD(const ALength: Integer; const AChar: Char): string; begin Result := Self; while Result.Length.MinorThan(ALength) do begin Result := Result + AChar; end; end; procedure TMStringHelper.SetChar(AIndex: Integer; const Value: Char); begin Self[AIndex] := Value; end; function TMStringHelper.Split(const ASeparator: string): TArray<string>; var strTemp : string; intPos : Integer; intIndex: Integer; begin SetLength(Result, 0); strTemp := Self; if ASeparator.IsEmpty then begin Exit; end; intPos := System.Pos(ASeparator, strTemp); intIndex := 0; while intPos > 0 do begin SetLength(Result, intIndex.Succ); Result[intIndex] := strTemp.Copy(1, intPos.Pred).Trim; System.Delete(strTemp, 1, intPos + ASeparator.Length.Pred); intPos := System.Pos(ASeparator, strTemp); intIndex.Inc; end; SetLength(Result, intIndex.Succ); Result[intIndex] := strTemp; end; function TMStringHelper.Split(const ASeparator: Char): TArray<string>; var strSep: string; begin strSep := ' '; {$IFDEF ANDROID} strSep[0] := ASeparator; {$ELSE} strSep[1] := ASeparator; {$ENDIF} Result := Split(strSep); end; function TMStringHelper.ToAnsi: AnsiString; begin Result := RawByteString(Self); end; function TMStringHelper.ToBase64: string; var stmInput : TStringStream; stmResult: TStringStream; begin Result := EmptyStr; if Self.IsEmpty then begin Exit; end; stmInput := TStringStream.Create(Self); stmResult := TStringStream.Create; stmResult.SetSize(stmInput.Size); TNetEncoding.Base64.Encode(stmInput, stmResult); Result := stmResult.DataString; stmInput.DisposeOf; stmResult.DisposeOf; end; function TMStringHelper.ToFloat(const ADefValue: Extended): Extended; begin Result := StrToFloatDef(Self, 0); end; function TMStringHelper.ToInteger(const ADefValue: Integer; const IsHex: Boolean): Integer; begin {$IF CompilerVersion = 31.0} Result := ADefValue; {$ENDIF} case IsHex of True : Result := StrToIntDef('$' + Self, ADefValue); False: Result := StrToIntDef(Self, ADefValue); end; end; function TMStringHelper.ToJSON: TJSONObject; begin Result := TJSONObject.ParseJSONValue(Self) as TJSONObject; end; function TMStringHelper.ToLower: string; begin Result := LowerCase(Self); end; function TMStringHelper.ToUpper: string; begin Result := UpperCase(Self); end; function TMStringHelper.ToUTF8: string; begin Result := string(UTF8Encode(Self)); end; function TMStringHelper.Trim: string; begin Result := System.SysUtils.Trim(Self); end; function TMStringHelper.TrimLeft: string; begin Result := System.SysUtils.TrimLeft(Self); end; function TMStringHelper.TrimRight: string; begin Result := System.SysUtils.TrimRight(Self); end; function TMStringHelper.Unaccent: string; const STR_ACCENTS = 'ÁÀÂÃÄÉÈÊÊËÍÌÎÏÓÒÔÕÖÚÙÛÜÇÑÝáàâãäéèêêëíìîïóòôõöúùûüçñý'; STR_NO_ACCENTS = 'AAAAAEEEEEIIIIOOOOOUUUUCNYaaaaaeeeeeiiiiooooouuuucny'; {$IFDEF ANDROID} INT_START = 0; INT_END = 1; {$ELSE} INT_START = 1; INT_END = 0; {$ENDIF} var i : Integer; intPos: Integer; begin Result := Self; for i := INT_START to Result.Length - INT_END do begin intPos := System.Pos(Result[i], STR_ACCENTS); if intPos > 0 then begin Result[i] := STR_NO_ACCENTS[intPos - INT_END]; end; end; end; function TMStringHelper.Unquote: string; var intIndex: Integer; begin Result := Self; {$IFDEF ANDROID} intIndex := 0; {$ELSE} intIndex := 1; {$ENDIF} case Result[intIndex].IsInArray(['"', #39]) of False: Exit; True : Result.Delete(1, 1); end; if Result[Result.Length{$IFDEF ANDROID} - 1 {$ENDIF}].IsInArray(['"', #39]) then begin Result.Delete(Result.Length, 1); end; end; end. |
E eu posso começar a usar isso já?
Eu costumo dizer que não existem restrições (além das óbvias restrições de tecnologia) para o que você pode fazer em termos de desenvolvimento, a não ser a sua própria limitação. Utilizar Class Helpers é uma opção, mas que traz consigo varias vantagens. Aumentar a produtividade, simplificar o código e automatizar ações são algumas destas vantagens. Contudo, há um preço a se pagar…
O sucesso – ou o fracasso – do uso de Class Helpers vai depender diretamente do nível de maturidade dos desenvolvedores envolvidos neste processo. Desenvolvedores menos experientes tendem a desconhecer, ignorar ou rejeitar seu uso. Programadores mais experientes, os quais já “aprenderam” a fazer as coisas de outra maneira ou vêm de versões do IDE que não suportam esta funcionalidade terão muita dificuldade em assimilar e usar Class Helpers. Minha dica é: use sempre que puder, mas tenha em mente que, dependendo da situação, isso pode trazer mais transtornos que vantagens.
E, apesar de que muitos autores e desenvolvedores digam que não é prudente utilizar Class Helpers para modificar o comportamento de classes que podem ser estendidas, imaginem, em um cenário em que o número de desenvolvedores é realmente numeroso e a aplicação já sofre com o tamanho final do arquivo compilado. Neste cenário, se cada desenvolvedor estender uma classe para sua utilização – e vale lembrar que, em quase todos os casos de sobrescrita, esta é feita através da diretiva virtual, a qual, ao contrário da diretiva dynamic, gera uma cópia do método sobrescrito em cada extensão para facilitar o processamento em detrimento do tamanho final do arquivo compilado -, faremos com que o executável fique ainda mais volumoso, o que dificulta processos de atualização pela internet, sem contar a própria memória consumida pela aplicação. Mas, enfim, essa é uma discussão para outro momento.
Espero que este artigo possa ajudar a elucidar o mistério em torno dos Class Helpers e sua utilização e que ele possa, como coloquei lá no título, aumentar sua produtividade e tornar seu código mais eficiente.
E aqui você pode fazer o download de um pequeno conjunto de Class Helpers muito úteis e demonstrados aqui.
Boa tarde, atualmente uso XE2. Quando compilo o código abaixo retorna o seguinte erro:”[DCC Error] UEnumerator.pas(15): E2474 Record type required”.
type
TDias = (Domingo, Segunda, Terca, Quarta, Quinta, Sexta, Sabado);
TDiasHelper = record helper for TDias
function GerValue : String;
end;
Boa noite.
Você consegue colocar todo o conteúdo da unit pra eu poder dar uma olhada?
Abraços.
Boa tarde.
Fiz um teste com o Delphi Tokyo (não tenho mais o XE2) e o Código abaixo funcionou perfeitamente. O seu problema pode ser relacionado à versão do Delphi.
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
type
TForm1 = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
TDias = (Domingo, Segunda, Terca, Quarta, Quinta, Sexta, Sabado);
TDiasHelper = record helper for TDias
function GetName: string;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TDiasHelper }
function TDiasHelper.GetName: string;
begin
case Self of
Domingo: Result := ‘Domingo’;
Segunda: Result := ‘Segunda’;
Terca : Result := ‘Terça’;
Quarta : Result := ‘Quarta’;
Quinta : Result := ‘Quinta’;
Sexta : Result := ‘Sexta’;
Sabado : Result := ‘Sábado’;
end;
end;
end.
Abraço.
Tentando usar um class helper no FMX para um TEdit e não vai.
Usava o mesmo esquema na VCL e funcionava normalmente. Bem estranho.
Primeiramente gostaria de te dá os Parabéns!
esses seus Classes Helper ficou top demais!
Esses arquivos estão disponíveis em algum repositório ?
poderia compartilhar a UNIT Helper.Integer ??
Olá Danilo.
Obrigado!
Em breve, quando eu for escrever o artigo sobre a API REST usando Datasnap e padrões de projeto, esses arquivos estarão disponíveis nos fontes do projeto. Por enquanto, segue o fonte do class helper para Integer.
Abraço.
unit Helper.Integer;
interface
type
TIntegerHelper = record helper for Integer
procedure Add(const AValue: Integer);
procedure Subtract(const AValue: Integer);
function Equals(const AVal: Integer): Boolean;
function Differs(const AVal: Integer): Boolean;
function Pred: Integer;
function Succ: Integer;
function BiggerThan(const AInt: Integer): Boolean;
function MinorThan(const AInt: Integer): Boolean;
procedure Inc(const AStep: Integer = 1);
procedure Dec(const AStep: Integer = 1);
function ToString: string;
function ToHex: string; overload;
function ToHex(const ADigits: Integer): string; overload;
end;
implementation
uses
System.SysUtils;
{ TIntegerHelper }
procedure TIntegerHelper.Add(const AValue: Integer);
begin
Self := Self + AValue;
end;
function TIntegerHelper.BiggerThan(const AInt: Integer): Boolean;
begin
Result := Self > AInt;
end;
procedure TIntegerHelper.Dec(const AStep: Integer);
begin
System.Dec(Self, AStep);
end;
function TIntegerHelper.Differs(const AVal: Integer): Boolean;
begin
Result := Self <> AVal;
end;
function TIntegerHelper.Equals(const AVal: Integer): Boolean;
begin
Result := Self = AVal;
end;
procedure TIntegerHelper.Inc(const AStep: Integer);
begin
System.Inc(Self, AStep);
end;
function TIntegerHelper.MinorThan(const AInt: Integer): Boolean;
begin
Result := Self < AInt; end;function TIntegerHelper.Pred: Integer; begin Result := System.Pred(Self); end;procedure TIntegerHelper.Subtract(const AValue: Integer); begin Self := Self - AValue; end;function TIntegerHelper.Succ: Integer; begin Result := System.Succ(Self); end;function TIntegerHelper.ToHex(const ADigits: Integer): string; begin Result := IntToHex(Self, ADigits); end;function TIntegerHelper.ToHex: string; begin Result := IntToHex(Self); end;function TIntegerHelper.ToString: string; begin Result := IntToStr(Self); end;end.