Search code examples
delphidelphi-11-alexandria

How to properly use a class function to CustomSort a TStringList?


In Delphi, I created a small class like this:

TFilesSorter = class
public
  constructor Create(ExtOrderList: TStrings);
  function SoryByExt(List: TStringList; Index1, Index2: Integer): Integer;
private
  ExtOrder: TStrings;
end;

I created a class because the SoryByExt function needs an ordered list of extensions (ExtOrder) used in the sort.

When I try to use my class function with CustomSort, like this:

FilesSorter := TFilesSorter.Create(ExtensionsList);
try
  SomeTStringList.CustomSort(FilesSorter.SoryByExt);
finally
  FilesSorter.Free;
end;

I get an error:

E2009 Incompatible types: 'regular procedure and method pointer'

Now I understand why (it works only with a non-class function), but I'm wondering how to use CustomSort when you need another variable (my ordered list of extension used during the sort process) without using global variables? I want to separate the responsibilities and not have shared variables.

What is the proper way to do this (I use Delphi 11)?


Solution

  • TStringList.CustomSort() does not support non-static class methods for its sort routine. So, when using a standard TStringList, if you need to access an external variable from inside your sort routine then it would have to be a global variable. Or, since the sort routine does have access to the TStringList that is being sorted, you could store a pointer to the external variable in one of the entries of the TStringList.Objects property (if you are not using it for something else, that is).

    Otherwise, an alternative option would be to derive a new class from TStringList and add whatever members you want to it, and then replace the original TStringList with your custom TStringList. That way, your sort routine can then typecast its List parameter to that derived class to access the extra members you added to it.

    For example, in this case, TFilesSorter itself could be the new TStringList descendant, eg:

    TFilesSorter = class(TStringList)
    public
      constructor Create(ExtOrderList: TStrings);
      function SoryByExt(List: TStrings);
    private
      ExtOrder: TStrings;
    end;
    
    constructor TFilesSorter.Create(ExtOrderList: TStrings);
    begin
      inherited Create;
      ExtOrder := ExtOrderList;
    end;
    
    function doSoryByExt(List: TStringList; Index1, Index2: Integer): Integer;
    begin
      // use TFilesSorter(List).ExtOrder to compare
      // List.Strings[Index1] with List.Strings[Index2]
      // as needed...
      Result := ...;
    end;
    
    function TFilesSorter.SoryByExt(List: TStrings);
    begin
      Self.Assign(List);
      Self.CustomSort(doSoryByExt);
      List.Assign(Self);
    end;
    
    ...
    
    FilesSorter := TFilesSorter.Create(ExtensionsList);
    try
      FilesSorter.SoryByExt(SomeTStringList);
    finally
      FilesSorter.Free;
    end;