Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 04/06/24 in all areas

  1. Hi mates, I have something on my mind but I couldn't implement it correctly, imagine a generic interface, some classes inherited from that interface, and one method in each class with the same name, now I'm trying to use this interface type every where for different approaches but it doesn't compile correctly. Please have a look at the code if you get a chance and share your thoughts with me, I do appreciate you in advance. The question is how can I implement such an idea properly and safely? I have attached a sample project to save you time too. unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Rtti; type IMyInterface<T> = interface function DoSomething: T; end; TMyClass<T> = class(TInterfacedObject, IMyInterface<T>) function DoSomething: T; end; TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private { Private declarations } function UseInterface<T>(obj: IMyInterface<T>): T; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} { TMyClass<T> } function TMyClass<T>.DoSomething: T; var ctx: TRttiContext; typ: TRttiType; begin ctx := TRttiContext.Create; typ := ctx.GetType(TypeInfo(T)); if typ.TypeKind = tkInteger then Result := 20 // E2010 Incompatible types: 'T' and 'Integer' else if typ.TypeKind = tkString then Result := T('Hello') // E2089 Invalid typecast else if typ.AsInstance.MetaclassType.InheritsFrom(TStringList) then Result := (typ.AsInstance.MetaclassType.InitInstance(typ) as TStringList) //E2010 Incompatible types: 'T' and 'TStringList' else Result := Default(T); ctx.Free; end; { TForm1 } function TForm1.UseInterface<T>(obj: IMyInterface<T>): T; begin Result := obj.DoSomething; end; procedure TForm1.FormCreate(Sender: TObject); var obj1: IMyInterface<Integer>; obj2: IMyInterface<String>; obj3: IMyInterface<TStringList>; begin try obj1 := TMyClass<Integer>.Create; obj2 := TMyClass<String>.Create; obj3 := TMyClass<TStringList>.Create; ShowMessage(UseInterface<Integer>(obj1).ToString); ShowMessage(UseInterface<String>(obj2)); ShowMessage(UseInterface<TStringList>(obj3).Text); except on E: Exception do Writeln('Exception: ', E.ClassName, ': ', E.Message); end; end; end. Generic Interface.zip
  2. Anders Melander

    NEW INDY REPO (CLONE) FOR ATHENS 12.1 UPDATES

    That's not how you do it. I doubt Remy will have time or motivation to look at whatever it is you have done. Fork the original repository. Make a branch. Apply your changes. Create a pull request to have your changes merged into the original repository. 2-4 should be done once per separate issue. A single issue that makes 20 unrelated changes probably has zero chance of being accepted.
  3. In XE7 and later, you should use the GetTypeKind() intrinsic function instead of using TypeInfo() comparisons: https://delphisorcery.blogspot.com/2014/10/new-language-feature-in-xe7.html case GetTypeKind(T) of tkInteger: PInteger(@Result)^ := 10; tkLString: PAnsiString(@Result)^ := 'Hello'; tkUString: PUnicodeString(@Result)^ := 'Hello'; ... end;
  4. First, thank you for your response. Second, I thought so but! It seems using RTTI's TValue it is possible to handle this situation somehow. I'm just not sure if everything goes right with this code or not at the end, I tested with "ReportMemoryLeaksOnShutdown := True;" and there is no memory leak. Please have a look at the final version and share your thoughts with me. Best regards. type IMyInterface<T> = interface ['{D68085A3-6AFB-46D9-A4EE-B46563758127}'] function DoSomething: T; end; TMyClass<T> = class(TInterfacedObject, IMyInterface<T>) function DoSomething: T; end; TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } function UseInterface<T>(obj: IMyInterface<T>): T; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} { TMyClass<T> } function TMyClass<T>.DoSomething: T; var ctx: TRttiContext; typ: TRttiType; val: TValue; begin ctx := TRttiContext.Create; typ := ctx.GetType(TypeInfo(T)); if typ.TypeKind = tkInteger then val := 20 else if (typ.TypeKind = tkString) or (typ.TypeKind = tkUString) then val := 'Hello' else if typ.AsInstance.MetaclassType.InheritsFrom(TStringList) then begin val := TStringList.Create; val.AsType<TStringList>.Add('Hello from StringList'); end; Result := Val.AsType<T>; ctx.Free; end; { TForm1 } function TForm1.UseInterface<T>(obj: IMyInterface<T>): T; begin Result := obj.DoSomething; end; procedure TForm1.Button1Click(Sender: TObject); var obj1: IMyInterface<Integer>; obj2: IMyInterface<String>; obj3: IMyInterface<TStringList>; lvstr: TStringList; begin try try obj1 := TMyClass<Integer>.Create; obj2 := TMyClass<String>.Create; obj3 := TMyClass<TStringList>.Create; ShowMessage(UseInterface<Integer>(obj1).ToString); ShowMessage(UseInterface<String>(obj2)); lvstr := UseInterface<TStringList>(obj3); ShowMessage(lvstr.Text); except on E: Exception do ShowMessage('Exception: ' + E.ClassName + ': ' + E.Message); end; finally lvstr.Free; obj1 := nil; obj2 := nil; obj3 := nil; end; end; Generic Interface-final.zip
  5. David Heffernan

    What new features would you like to see in Delphi 13?

    This isn't really a great example. The sort of thing that I want to do with records, but cannot, is this: type A = record; B = record; A = record function foo: B; end; B = record function bar: A; end; I can get round this using helpers right now, but I don't understand why I can't do this directly as above.
×