使用搜索字符串搜索通用列表,ERROR E2034 TOO MANY PARAMETER

时间:2013-07-19 11:49:37

标签: delphi

我想我对编写代码的方式的理解仍然非常有限。我尝试从SEARCH GENERIC LISTS修改解决方案,但我不能以他接受任意关键字作为搜索参数的方式更改代码

unit Unit_TsearchableTList;

interface

uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons,
  contnrs, Generics.Collections;

type
  TSearchableObjectList<T: class> = class(TObjectList<T>)

  public type
    TPredicate = reference to function(aItem: T; asearchValue: String): boolean;
  public
    function search(aFound: TPredicate<T>; asearchValue: String): T;
  end;

implementation

function TSearchableObjectList<T>.search(aFound: TPredicate<T>;
  asearchValue: String): T;
var
  item: T;
begin
  for item in Self do
    * * * * * * * * COMPILE ERROR IS HERE * * * * * * * * * * * * * * * *
      * ! ! ! ! ! !
  if aFound(item, asearchValue) then
    Exit(item);
  Result := nil;
end;

end.

用法示例:

type
  TReplaceElementNames = class
    FindName: String;
    ReplaceName: String;
    ReplacementCondition: TReplacementCondition; // not relevant code
  end;

var
  LookUpList: TList<TReplaceElementNames>;
  search    : TReplaceElementNames;

begin
  LookUpList := TSearchableObjectList<TReplaceElementNames>.Create;

  search := LookUpList.search(
    function(aItem: TReplaceElementNames; searchname: String): boolean
    begin
      Result := aItem.FindName = searchname;
    end);

2 个答案:

答案 0 :(得分:2)

您在代码中定义的类型为TPredicate。但是你继续使用TPredicate<T>,这是SysUtils中定义的类型。只需更换

TPredicate<T>

TPredicate

在您的代码中,它将编译。


话虽如此,如果您在接受的答案中使用了代码,那会更简单。因为变量捕获用于提供搜索字符串,所以不需要两个参数谓词。

答案 1 :(得分:1)

根据定义,谓词是somethign,只需要一个参数,如http://docwiki.embarcadero.com/Libraries/XE2/en/System.SysUtils.TPredicate

那么,我们如何才能将更多参数传递给它,比如要比较什么?我们通过捕获ocntext并生成固定上下文的新临时函数来实现。

修改你的例子(我试着详细,以便你可以跟踪这些步骤):

Type CanCompareWithString<T> = function (const Value:T; const Target: string): boolean;
// overcoming Delphi limitation

Function CreatePredicateFunction<T>(Const Target: String; Const Matcher: CanCompareWithString<T>): TPredicate<T>;
begin
   Result := function // creating new function (more correct: new closure)
                (Arg1: T): Boolean // see top link to Delphi docs
                begin
                  Result := 
                     Matcher // capturing the passed function
                     ( Arg1, 
                       Target ) // capturing the target value
                end;    // finished creating closure
    end;


  TSearchableObjectList<T: class> = class(TObjectList<T>)
  public
    function search(aFound: TPredicate<T>): T; overload;
    function search( asearchValue: String; Matcher: CanCompareWithString<T>): T; overload;
  end;

function TSearchableObjectList<T>.search(aFound: TPredicate<T>): T;
var
  item: T;
begin
  for item in Self do
  if aFound(item) then
    Exit(item);
  Result := Default(T);
end;

function TSearchableObjectList<T>.search( asearchValue: String;  Matcher: CanCompareWithString<T>): T;
begin
  Result := 
    Search(
       CreatePredicateFunction(
           Matcher, aSearchValue)
    ); 
end;

你怎么用?希望是这样的:

function StringMatcher(const Value:string; const Target: string): boolean;
begin
   Result := Value = Target;
end;

var L_S : TSearchableObjectList<String>; S: String;

S := L_S.Search('abcde', StringMAtcher);

现在你可能会问“为什么?为什么要使用StringMatcher?”

问题在于,在Delphi中,您无法在具有类型的运算符上添加部分约束(Scala中的内容称为外部类型AFAIR)。你就是无法编译

function Equal<T>(const value: String): boolean;
begin
  Result := T = Value;
end;

function Sum<U>(const value1, value2: U): U;
begin
  Result := value1 + value2;
end;

Delphi现在不是那个类型T,也不能确定它是否可以与字符串进行比较,因此它无法编译“T = Value”。

Delphi现在不是U的类型,也不能确定它是否可以添加,因此它无法编译“value1 + value2”。

这是一个很大的限制 - 但事实就是如此。

查看以下类型的实现:

你会看到需要哪种样板来完成一个类似的任务(但更简单一个!那里的任务只是比较T到T,而不是T到String)。