After two introductory posts, here is the actual source code of the custom variant used to implement dynamic method invocation. It is only a rough working prototype. Time permitting, I'd integrate it into the actual class hosting the data (something I did in the past for a different demo). And will try to make the code easier to reuse. Anyway, here is goes. This rather complex code allows you to call method that don't actually exist, as you'll pass the method name as a string parameter to a single processing function. The same could be done for functions and properties. Enjoy.
unit
DynamicDslVariant;interface
uses
TypInfo, Variants, Classes;function
VarDSLDateTimeCreate(const
AValue: TDateTime): Variant;overload
;implementation
uses
VarUtils, SysUtils, DateUtils, WIndows, Dialogs;type
TDslDateTimeVariantType =class
(TPublishableVariantType)protected
function
GetInstance(const
V: TVarData): TObject;override
;public
procedure
Clear(var
V: TVarData);override
;procedure
CastTo(var
Dest: TVarData;const
Source: TVarData;const
AVarType: TVarType);override
;function
DoFunction(var
Dest: TVarData;const
V: TVarData;const
Name:string
;const
Arguments: TVarDataArray): Boolean;override
;function
DoProcedure(const
V: TVarData;const
Name:string
;const
Arguments: TVarDataArray): Boolean;override
;end
;var
DslDateTimeVariantType: TDslDateTimeVariantType =nil
;type
TDslDateTimeData =class
(TPersistent)private
FDateTime: TDateTime;public
constructor
Create(const
AValue: TDateTime);overload
;function
AsString:string
;property
DateTime: TDateTimeread
FDateTimewrite
FDateTime;end
;{ Helper record for variant data }
TDslDateTimeVarData =packed
record
VType: TVarType; Reserved1, Reserved2, Reserved3: Word; VDateTime: TDslDateTimeData; Reserved4: DWord;end
;{ TDslDateTimeVariantType }
procedure
TDslDateTimeVariantType.CastTo(var
Dest: TVarData;const
Source: TVarData;const
AVarType: TVarType);var
LTemp: TVarData;begin
if
Source.VType = VarTypethen
case
AVarTypeof
varString: VarDataFromStr(Dest, TDslDateTimeVarData (Source).VDateTime.AsString);else
VarDataInit(LTemp);try
LTemp.VType := varDate; LTemp.VDate := TDslDateTimeVarData (Source).VDateTime.DateTime; VarDataCastTo(Dest, LTemp, AVarType);finally
VarDataClear(LTemp);end
;end
else
inherited
;end
;procedure
TDslDateTimeVariantType.Clear(var
V: TVarData);begin
V.VType := varEmpty; FreeAndNil(TDslDateTimeVarData(V).VDateTime);end
;function
TDslDateTimeVariantType.DoFunction(var
Dest: TVarData;const
V: TVarData;const
Name:string
;const
Arguments: TVarDataArray): Boolean;begin
ShowMessage ('fn calling '
+ name);// Dest :=
Result := True;end
;function
TDslDateTimeVariantType.DoProcedure(const
V: TVarData;const
Name:string
;const
Arguments: TVarDataArray): Boolean;var
tmp:string
; value, month, day: Integer; tmpDate: TDateTime;begin
// ShowMessage ('proc calling ' + name);
if
Pos ('AM'
, Name) > 0then
begin
// parse and process...
tmp := StringReplace (Name,'AM'
,''
, []); value := StrToIntDef (tmp, 0); TDslDateTimeVarData(V).VDateTime.DateTime := RecodeTime (TDslDateTimeVarData(V).VDateTime.DateTime, value, 0, 0, 0);end
;if
Pos ('PM'
, Name) > 0then
begin
// parse and process...
tmp := StringReplace (Name,'PM'
,''
, []); value := StrToIntDef (tmp, 0); TDslDateTimeVarData(V).VDateTime.DateTime := RecodeTime (TDslDateTimeVarData(V).VDateTime.DateTime, value + 12, 0, 0, 0);end
;if
Pos ('NEXT'
, Name) > 0then
begin
// parse and process...
tmp := StringReplace (Name,'NEXT'
,''
, []);if
tmp ='MONDAY'
then
begin
tmpDate := Now; value := DayOfWeek(tmpDate); tmpDate := tmpDate + 7 - value + 2;// monday as 2nd day of the week
TDslDateTimeVarData(V).VDateTime.DateTime := DateOf (tmpDate) + TimeOf (TDslDateTimeVarData(V).VDateTime.DateTime);end
;end
;if
Pos ('DEC'
, Name) > 0then
begin
month := 12;// parse and process...
tmp := StringReplace (Name,'DEC'
,''
, []); day := StrToIntDef (tmp, 0); TDslDateTimeVarData(V).VDateTime.DateTime := RecodeDate (TDslDateTimeVarData(V).VDateTime.DateTime, YearOf (now), month, day);end
; Result := True;end
;function
TDslDateTimeVariantType.GetInstance(const
V: TVarData): TObject;begin
Result := TDslDateTimeVarData(V).VDateTime;end
;{ TDslDateTimeData }
function
TDslDateTimeData.AsString:string
;begin
Result := DateTimeToStr (FDateTime);end
;constructor
TDslDateTimeData.Create(const
AValue: TDateTime);begin
FDateTime := AValue;end
;// variant construction
function
VarDSLDateTimeCreate(const
AValue: TDateTime): Variant;begin
VarClear(Result); TDslDateTimeVarData(Result).VType := DslDateTimeVariantType.VarType; TDslDateTimeVarData(Result).VDateTime := TDslDateTimeData.Create(AValue);end
;initialization
DslDateTimeVariantType := TDslDateTimeVariantType.Create;finalization
FreeAndNil(DslDateTimeVariantType);end
.