chkaufmann 17 Posted February 4, 2020 Hi, I try to create this helper: TComponentHelper = class helper for TComponent public function FindComponents<I:IInterface>: IBSEnumerable<I>; overload; function FindComponents<T:class>: IBSEnumerable<T>; overload; end; but I get an error "methods with identical parameters". In my generic code I filter components either by using "InheritsFrom" or "Supports()". Therefore I need IInterface and class in the declaration or is there another way to do that? Christian Share this post Link to post
Stefan Glienke 2002 Posted February 4, 2020 Overloads based on generic type constraint are not possible. Personally I would just make one method without constraint and use GetTypeKind(T) internally to decide if its tkInterface or tkClass and simply raise an exception if anyone put anything but a class or interface into T. Share this post Link to post
chkaufmann 17 Posted February 4, 2020 But if I don't declare T:class I cannot use it in the InheritsFrom() method. Same for an IInterface with the Support method: function TComponentHelper.FindComponents<I:IInterface>: IBSEnumerable<I>; var ix : Integer; lst : IBSList<I>; tmp : I; begin lst := TBSGenerics.GenList<I>; for ix := 0 to ComponentCount - 1 do if Supports(Components[ix], I, tmp) then lst.Add(tmp); Result := tmp; end; function TComponentHelper.FindComponents<T:class>: IBSEnumerable<T>; var ix : Integer; lst : IBSList<T>; tmp : T; begin Assert(T.InheritsFrom(TComponent), 'Nur für Subklassen von TComponent'); lst := TBSGenerics.GenList<T>; for ix := 0 to ComponentCount - 1 do if Components[ix].InheritsFrom(T) then begin TComponent(tmp) := Components[ix]; lst.Add(tmp); end; Result := lst; end; Christian Share this post Link to post
Lars Fosdal 1792 Posted February 4, 2020 Must it be an overload? Why not FindComponentsByClass vs FindComponentsWithInterface ? Share this post Link to post
Remy Lebeau 1396 Posted February 4, 2020 (edited) 10 hours ago, chkaufmann said: I get an error "methods with identical parameters". In my generic code I filter components either by using "InheritsFrom" or "Supports()". Therefore I need IInterface and class in the declaration or is there another way to do that? You can't overload on return type alone. You need different parameter lists. That is exactly what the error message is saying. So a simple solution would be to change the return value into an output parameter, eg: TComponentHelper = class helper for TComponent public procedure FindComponents<I:IInterface>(out Enum: IBSEnumerable<I>); overload; procedure FindComponents<T:class>(out Enum: IBSEnumerable<T>); overload; end; procedure TComponentHelper.FindComponents<I:IInterface>(out Enum: IBSEnumerable<I>); var ix : Integer; lst : IBSList<I>; tmp : I; begin lst := TBSGenerics.GenList<I>; for ix := 0 to ComponentCount - 1 do begin if Supports(Components[ix], I, tmp) then lst.Add(tmp); end; Enum := lst; end; procedure TComponentHelper.FindComponents<T:class>(out Enum: IBSEnumerable<T>); var ix : Integer; lst : IBSList<T>; tmp : T; comp: TComponent; begin Assert(T.InheritsFrom(TComponent), 'Nur für Subklassen von TComponent'); lst := TBSGenerics.GenList<T>; for ix := 0 to ComponentCount - 1 do begin comp := Components[ix]; if comp.InheritsFrom(T) then lst.Add(T(comp)); end; Enum := lst; end; Edited February 4, 2020 by Remy Lebeau Share this post Link to post
Remy Lebeau 1396 Posted February 4, 2020 (edited) On 2/4/2020 at 5:00 AM, chkaufmann said: But if I don't declare T:class I cannot use it in the InheritsFrom() method. Same for an IInterface with the Support method While it is true that you can't pass T itself directly without using a constraint on T, you can use T's RTTI to get its Interface Guid or Class Type at runtime, and then pass that to Supports()/InheritsFrom() instead of T. For example, something like this: uses ..., TypInfo; type TComponentHelper = class helper for TComponent public function FindComponents<T>: IBSEnumerable<T>; end; function TComponentHelper.FindComponents<T>: IBSEnumerable<T>; type PIInterface = ^IInterface; PTComponent = ^TComponent; var ix : Integer; lst : IBSList<T>; tmp : T; comp : TComponent; ClsType: TClass; IntfGuid: TGUID; begin case GetTypeKind(T){PTypeInfo(TypeInfo(T)).Kind} of tkClass: begin lst := TBSGenerics.GenList<T>; ClsType := GetTypeData(PTypeInfo(TypeInfo(T))).ClassType; for ix := 0 to ComponentCount - 1 do begin comp := Components[ix]; if comp.InheritsFrom(ClsType) then begin PTComponent(@tmp)^ = comp; lst.Add(tmp); end; end; end; tkInterface: begin lst := TBSGenerics.GenList<T>; IntfGuid := GetTypeData(PTypeInfo(TypeInfo(T))).Guid; for ix := 0 to ComponentCount - 1 do begin if Supports(Components[ix], IntfGuid, PIInterface(@tmp)^) then lst.Add(tmp); end; end; else raise ...; end; Result := lst; end; Edited February 5, 2020 by Remy Lebeau 1 Share this post Link to post
chkaufmann 17 Posted February 5, 2020 Thanks Remy, perfect solution. Christian Share this post Link to post