Class Helper in Delphi. Is it useful or not ?
Class Helper
The syntax for declaring a class helper is:
type
TMyClassHelper = class helper for TMyClass
memberList
end;
Example...
// my Class //
type
TMyClass = class
procedure MyProc;
function MyFunc: Integer;
end;
...
procedure TMyClass.MyProc;
var X: Integer;
begin
X := MyFunc;
end;
function TMyClass.MyFunc: Integer;
begin
...
end;
...
// Class Helper for TMyClass //
type
TMyClassHelper = class helper for TMyClass
procedure HelloWorld;
function MyFunc: Integer;
end;
...
procedure TMyClassHelper.HelloWorld;
begin
Writeln(Self.ClassName); // Self refers to TMyClass type, not TMyClassHelper
end;
function TMyClassHelper.MyFunc: Integer;
begin
...
end;
...
// Use of above Class and Class Helper //
var
X: TMyClass;
begin
X := TMyClass.Create;
X.MyProc; // Calls TMyClass.MyProc
X.HelloWorld; // Calls TMyClassHelper.HelloWorld
X.MyFunc; // Calls TMyClassHelper.MyFunc
We can declare a Class Helper to extend TStrings.
Example...
type
TStringsHelper = class helper for TStrings
public
function IsEmpty: Boolean;
end;
.....
function TStringsHelper.IsEmpty: Boolean;
begin
Result := Count = 0;
end;
....
procedure TForm1.Button1Click(Sender: TObject);
begin
if Memo1.Lines.IsEmpty then
Button1.Caption := 'Empty'
else
Button1.Caption := 'Filled';
end;
Class Helper are used extensively in Delphi RTL codes used in SYSTEM.PAS...
Example...
type
TSingleHelper = record helper for Single
private
function InternalGetBytes(Index: Cardinal): UInt8; inline;
function InternalGetWords(Index: Cardinal): UInt16; inline;
procedure InternalSetBytes(Index: Cardinal; const Value: UInt8); inline;
procedure InternalSetWords(Index: Cardinal; const Value: UInt16); inline;
function GetBytes(Index: Cardinal): UInt8;
function GetWords(Index: Cardinal): UInt16;
function GetExp: UInt64; inline;
function GetFrac: UInt64; inline;
function GetSign: Boolean; inline;
procedure SetBytes(Index: Cardinal; const Value: UInt8);
procedure SetWords(Index: Cardinal; const Value: UInt16);
procedure SetExp(NewExp: UInt64);
procedure SetFrac(NewFrac: UInt64);
procedure SetSign(NewSign: Boolean);
end;
When we should use Class helper?
Class Helper is a Type that associated with another Class, generally used to extend a class without using inheritance. We can introduce new functionalities with additional methods and properties which can be used with members of associated class. To declare a Class Helper we have to state a Helper name with associated Class name.
The syntax for declaring a class helper is:
type
TMyClassHelper = class helper for TMyClass
memberList
end;
Example...
// my Class //
type
TMyClass = class
procedure MyProc;
function MyFunc: Integer;
end;
...
procedure TMyClass.MyProc;
var X: Integer;
begin
X := MyFunc;
end;
function TMyClass.MyFunc: Integer;
begin
...
end;
...
// Class Helper for TMyClass //
type
TMyClassHelper = class helper for TMyClass
procedure HelloWorld;
function MyFunc: Integer;
end;
...
procedure TMyClassHelper.HelloWorld;
begin
Writeln(Self.ClassName); // Self refers to TMyClass type, not TMyClassHelper
end;
function TMyClassHelper.MyFunc: Integer;
begin
...
end;
...
// Use of above Class and Class Helper //
var
X: TMyClass;
begin
X := TMyClass.Create;
X.MyProc; // Calls TMyClass.MyProc
X.HelloWorld; // Calls TMyClassHelper.HelloWorld
X.MyFunc; // Calls TMyClassHelper.MyFunc
We can declare a Class Helper to extend TStrings.
Example...
type
TStringsHelper = class helper for TStrings
public
function IsEmpty: Boolean;
end;
.....
function TStringsHelper.IsEmpty: Boolean;
begin
Result := Count = 0;
end;
....
procedure TForm1.Button1Click(Sender: TObject);
begin
if Memo1.Lines.IsEmpty then
Button1.Caption := 'Empty'
else
Button1.Caption := 'Filled';
end;
Class Helper are used extensively in Delphi RTL codes used in SYSTEM.PAS...
Example...
type
TSingleHelper = record helper for Single
private
function InternalGetBytes(Index: Cardinal): UInt8; inline;
function InternalGetWords(Index: Cardinal): UInt16; inline;
procedure InternalSetBytes(Index: Cardinal; const Value: UInt8); inline;
procedure InternalSetWords(Index: Cardinal; const Value: UInt16); inline;
function GetBytes(Index: Cardinal): UInt8;
function GetWords(Index: Cardinal): UInt16;
function GetExp: UInt64; inline;
function GetFrac: UInt64; inline;
function GetSign: Boolean; inline;
procedure SetBytes(Index: Cardinal; const Value: UInt8);
procedure SetWords(Index: Cardinal; const Value: UInt16);
procedure SetExp(NewExp: UInt64);
procedure SetFrac(NewFrac: UInt64);
procedure SetSign(NewSign: Boolean);
end;
When we should use Class helper?
We should use Class Helper to extend a class when we cannot (or do not need to) rely on normal class inheritance and interface implementations. For example, if you want extra functionality for an existing instance class and for some reason you are not able to change the existing source. We can create a class helper to add extra functionality. A class helper cannot declare instance data, like new private fields (or properties that would read/write such fields).
But A class helper can add new methods (function, procedure).
So in general we should avoid extending your own classes. If you need to add some new functionality to your own custom classes then add the new members in the class implementation directly - not using a class helper.
Notes:
Class helpers can be stored in a separate unit, so you can add your own nifty class helpers. Be sure to give these units a easy to remember name like Class Helpers for helpers for the Classes unit.
Class Helper changes in new Delphi versions...
From Delphi XE 3 release you can also extend simple types like integer or string or TDateTime, and have construct
Example...
var
s : string;
begin
s := 'Delphi XE3 helpers';
s := s.ToUpper;
end;
Comments
Post a Comment