RAD Studio RAD 10.4 - my sample Create and Using Generics of various Type include calling External app (Notepad) do show resulted and close it in 3 seconds

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
my sample Create and Using Generics of various Type include calling External app (Notepad) do show resulted and close it in 3 seconds
Scenary:
  • MSWindows 10 Enterprise 64bits in VirtualBox VM (with 3GB + 2 vCPU)
  • RAD Studio 10.4 SADness (9797) full installed
  • Console 32bits project
prjCON_Generics_Constructor_to_Many_Type.png

[SHOWTOGROUPS=4,20]
Код:
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]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
[SHOWTOGROUPS=4,20]
Код:
unit uUnitSecond;

interface

//
// Remember: What is not private, for default, is public!
//

type
  IMyIntefaceSomeLikeThis = Interface
    ['{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxx}']   <--- Ctrl+Shift+G
  end;

  //
  TMyIntegerType1 = Integer;
  TMyIntegerType2 = type Integer;
  TMyIntegerType3 = ^Integer;

  //
  // TSomeClass<T: record> = class // OK!
  // TSomeClass<T: IMyIntefaceSomeLikeThis, record> = class // OK!
  // TSomeClass<T: IMyIntefaceSomeLikeThis, record , constructor> = class // Conflict between "record" and "constructor"!
  // TSomeClass<T: class> = class // OK!
  // TSomeClass<T: class, constructor> = class // OK!
  // TSomeClass<T: class, IMyIntefaceSomeLikeThis> = class // OK!
  // TSomeClass<T: class, IMyIntefaceSomeLikeThis, constructor> = class // OK!
  // TSomeClass<T: class, IMyIntefaceSomeLikeThis, record > = class // cannot have "Class" and "Record" together, of course!
  //
  // TSomeClass<T: Integer> = class // Type Integer is not a valid constraint!
  // TSomeClass<T: TMyIntegerType1> = class // Type Integer is not a valid constraint!
  // TSomeClass<T: TMyIntegerType2> = class // Type TMyIntegerType2 is not a valid constraint!
  // TSomeClass<T: TMyIntegerType3> = class // Type TMyIntegerType2 is not a valid constraint!
  //
  //
  //
  { valid CONSTRAINTS to Generics: none, class, interface, record and constructor or a combination above }
  //
  //
  TSomeClass<T: constructor> = class
    // you can have this sections:
    // ... -> private  // other unit dont see it
    // ... -> strict private // +(private) and only this class can see it
    // ... -> public
    //
    // allow access our "var" without necessity to create a object instance (in some cases)
    // private // 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;

implementation

{ 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 "ignoring" it to primitive types (in Integer case) or really using the "create" function?
  // 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
  //
end;

destructor TMyGroup.Destroy;
begin
  //
end;

function TMyGroup.GetFValue: string;
begin
  //
end;

procedure TMyGroup.SetFValue(const Value: string);
begin
  //
end;

end.
[/SHOWTOGROUPS]