my sample Create and Using Generics of various Type include calling External app (Notepad) do show resulted and close it in 3 seconds
Scenary:
Scenary:
- MSWindows 10 Enterprise 64bits in VirtualBox VM (with 3GB + 2 vCPU)
- RAD Studio 10.4 SADness (9797) full installed
- Console 32bits project
[SHOWTOGROUPS=4,20]
[/SHOWTOGROUPS]
Код:
program prjCON_Testing_Generics_Constructors_To_Types;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.Classes,
System.SysUtils,
Winapi.Windows,
Winapi.Messages,
ShellApi,
VCL.Dialogs,
uUnitSecond in 'uUnitSecond.pas'
// uUnitThird in 'uUnitThird.pas'
;
type // TMyOnlyInteger = Integer;
//
// Remember: What is not private, for default, is public!
//
TSomeClass<T: constructor> = class // it's necessary "have" a "constructor" for the "type" param
// you can have this sections:
// ... -> private // other unit dont see it
// ... -> strict private // +(private) and class inherited cannot see it
// ... -> public
//
// allow access our "var" without necessity to create a object instance (in some cases)
//
// try uncomment this clause:
{ strict } { private }
class
var
FValue: T;
// help get the "type" of our "type passed as param", returning the itself
// it would can be used to return the "classtype" (for example) or another more info, of course, etc...
// just im dont need here!
function GetGeneric: T;
// because definition above, is necessary that exist a "constructor" for the type passed as param
constructor Create;
end;
//
// creating a class only for test the "TSomeClass<T>" use!
// It would not be necessary create it!
// We would can use any other already that exist in the RAD!
TMyGroup = class
private
FName: string;
FValue: string;
function GetFValue: string;
procedure SetFValue(const Value: string);
published
property name: string read FName write FName;
property somevalue: string read GetFValue write SetFValue;
public
constructor Create;
destructor Destroy;
end;
{ TSomeClass<T> }
constructor TSomeClass<T>.Create;
begin
// inherited Create; // inherit the "create" ancestral default
//
// ****************************************************************
// constructor default because <T:Constructor> definition above!
// ****************************************************************
// why types like "integer" not causing AV or any error with this code?
//
// "Create", here, is representing the "creator" of "ancestral object"
// then, would be necessary see "how" the compiler treat this case!
//
// Would it can be "ignored" to primitive types (in Integer case) or really the "create" function is used?
// T = now use the "create default for all objects" (internal definition) = maybe in "systobj.h"
// because, "T" is just a "type" but "what type?"
FValue := T.Create;
end;
function TSomeClass<T>.GetGeneric: T;
begin
// just "return" the value in "class var FValue" if it was "private or strict private" for example
// of course, this return is of type of "T" passed
Result := FValue;
end;
{ TMyGroup }
constructor TMyGroup.Create;
begin
inherited Create;
end;
destructor TMyGroup.Destroy;
begin
inherited Destroy;
end;
function TMyGroup.GetFValue: string;
begin
Result := FValue;
end;
procedure TMyGroup.SetFValue(const Value: string);
begin
if not(FValue = Value) then
FValue := Value;
end;
// --------------------------------------------
var
someClassT1: TSomeClass<Integer>;
someClassT2: TSomeClass<string>;
someClassT3: TSomeClass<Double>;
someClassT4: TSomeClass<TDateTime>;
someClassT5: TSomeClass<TMyGroup>;
someClassT6: TSomeClass<Single>;
//
lMiliSecondsToWait: Integer = 3000;
lShowMyAccessViolation: boolean = false;
lShowMyFileOutPutTxt: boolean = true;
lShowMyShowMessageOnFreeObject: boolean = true;
//
i: Integer;
lClassName: string;
lMyFileOutPut: TextFile;
lWinExecReturn: Cardinal;
lMyFindWindowReturn: HWND;
lPostMessageReturn: LongBool;
procedure prcWaitMeSeeTheResulted(lCommandLineAndParam: PAnsiChar; lFindWindowText: PWideChar);
begin
// ShellExecute(0, nil, 'MyFileOutPut.txt', nil, nil, SW_SHOWNORMAL);
//
lWinExecReturn := WinExec(lCommandLineAndParam, SW_SHOW);
// ShowMessage('let me see it'); // more easy :)
//
if (lWinExecReturn > 0) then
Sleep(lMiliSecondsToWait); // thread main in wait mode...
//
lMyFindWindowReturn := FindWindow(nil, lFindWindowText);
//
if (lMyFindWindowReturn > 0) then
lPostMessageReturn := PostMessage(lMyFindWindowReturn, WM_CLOSE, 0, 0);
//
// if (lMyFindWindowReturn > 0) then
// BringWindowToTop(lMyFindWindowReturn);
end;
begin
//
ReportMemoryLeaksOnShutdown := true;
//
AssignFile(lMyFileOutPut, 'MyFileOutPut.txt');
Rewrite(lMyFileOutPut);
//
try
try
someClassT1 := TSomeClass<Integer>.Create; // Integer types, have a creator in deep-code or in deep-web? :)
someClassT1.FValue := 1234;
i := someClassT1.GetGeneric;
WriteLn(lMyFileOutPut, 'my i value: ', i);
//
someClassT2 := TSomeClass<string>.Create;
someClassT2.FValue := '-1234-';
i := StrToIntDef(someClassT2.GetGeneric, -9);
WriteLn(lMyFileOutPut, 'my i value: ', i);
//
someClassT3 := TSomeClass<Double>.Create;
someClassT3.FValue := 5.1234;
{ Round() = see TRoundingMode modes / exception = EInvalidOp = out limits }
i := Round(someClassT3.GetGeneric);
WriteLn(lMyFileOutPut, 'my i value: ', i);
//
someClassT4 := TSomeClass<TDateTime>.Create;
someClassT4.FValue := now;
i := Round(someClassT4.GetGeneric);
WriteLn(lMyFileOutPut, 'my i value: ', i);
//
someClassT5 := TSomeClass<TMyGroup>.Create;
someClassT5.FValue.name := 'Hello World';
//
someClassT5.FValue.somevalue := someClassT1.ClassName;
WriteLn(lMyFileOutPut, 'my i value: ', i, ' ', someClassT5.FValue.name, ' ', someClassT5.FValue.somevalue);
//
someClassT5.FValue.somevalue := someClassT2.ClassName;
WriteLn(lMyFileOutPut, 'my i value: ', i, ' ', someClassT5.FValue.name, ' ', someClassT5.FValue.somevalue);
//
someClassT5.FValue.somevalue := someClassT3.ClassName;
WriteLn(lMyFileOutPut, 'my i value: ', i, ' ', someClassT5.FValue.name, ' ', someClassT5.FValue.somevalue);
//
someClassT5.FValue.somevalue := someClassT4.ClassName;
WriteLn(lMyFileOutPut, 'my i value: ', i, ' ', someClassT5.FValue.name, ' ', someClassT5.FValue.somevalue);
//
someClassT5.FValue.somevalue := someClassT5.ClassName;
WriteLn(lMyFileOutPut, 'my i value: ', i, ' ', someClassT5.FValue.name, ' ', someClassT5.FValue.somevalue);
//
// not necessary here for test using "class var" and we dont have creating any obj instance!
// only accessing a memory space already reserved for my var!
// someClassT6 := TSomeClass<Single>.Create; // not necessary in this case!
someClassT6.FValue := 1.54;
WriteLn(lMyFileOutPut, 'my i value: ', someClassT6.FValue);
// WriteLn(lMyFileOutPut, someClassT6.ClassName); // "AV" here
//
if lShowMyAccessViolation then
begin
// causing the AV ... :))) i'm bad-guy!
//
someClassT1.FValue := StrtoInt('a1234'); // it will cause an "AV" = "a string is not a integer"
i := someClassT1.GetGeneric;
WriteLn(lMyFileOutPut, 'my i value: ', i);
end;
except
on E: Exception do
WriteLn(lMyFileOutPut, E.ClassName, ': ', E.Message);
end;
finally
CloseFile(lMyFileOutPut);
//
if not(someClassT5.FValue = nil) then
// free my TGroup class if necessary to avoid leak memory
begin
someClassT5.FValue.Free;
//
if lShowMyShowMessageOnFreeObject then
ShowMessage('Free my someClassT5.FValue = TGroup created');
end;
//
if lShowMyFileOutPutTxt and FileExists('MyFileOutPut.txt') then
prcWaitMeSeeTheResulted( { }
'notepad.exe MyFileOutPut.txt', { app.exe param }
'MyFileOutPut.txt - Bloco de Notas' { filename.ext - Notepad }
);
//
end;
end.
(* debuggin the process...
my unit, line 122
someClassT1 := TSomeClass<Integer>.Create;
-------------------------------------------
my unit, line 42
begin
constructor TSomeClass<T>.Create;
-------------------------------------------
System.pas, line 18999
function _ClassCreate(InstanceOrVMT: Pointer; Alloc: ShortInt): Pointer;
PUSH EDX
...
-------------------------------------------
my unit, line 43
inherited Create;
-------------------------------------------
System.pas, line 17670
constructor TObject.Create;
-------------------------------------------
my unit, line 44
constructor TSomeClass<T>.Create;
FValue := T.Create;
-------------------------------------------
System.pas, line 19051
function _AfterConstruction(const Instance: TObject): TObject;
begin
...
-------------------------------------------
my unit, line 123
someClassT1.FValue := 1234;
-------------------------------------------
my unit, line 48
function TSomeClass<T>.GetGeneric: T;
begin
...
-------------------------------------------
my unit, line 125
WriteLn(lMyFileOutPut, 'my i value: ', i);
...
...
my unit, line 180
if not(someClassT5.FValue = nil) then
...
-------------------------------------------
*)
[/SHOWTOGROUPS]