Delphi通用列表到字符串

时间:2015-08-07 09:54:29

标签: delphi generics

我正在查看一个通用列表,该列表可以根据特定字段写入任何对象的字符串数组。基本列表将包含许多后代。声明的代码如下所示,编译良好:

unit TestList;

interface

uses
  System.Classes, System.Rtti, System.Generics.Collections, system.SysUtils;

type
  TMakeString<T> = reference to function(const input: T): String;

  TMyList<T>=class(TList<T>)
  protected
    function GenericAsString(const Value): string;
    Function CastToString(const Value: T): string; virtual;
  public
    Function MakeArray:TArray<string>;
  end;

  TMyObject=class(TObject)
  private
    fname: string;
  public
    property Name:string read fname write FName;
  end;

  TMyObjectList<T:TMyObject>=class(TMyList<T>)
  protected
    Function CastToString(const Value: T): string; override;
  end;

implementation

{ TMyList<T> }

function TMyList<T>.CastToString(const Value: T): string;
begin
  result:='';
  if TypeInfo(T) = TypeInfo(string) then
    Result := GenericAsString(Value);
end;

function TMyList<T>.GenericAsString(const Value): string;
begin
  Result := String(Value);
end;

function TMyList<T>.MakeArray: TArray<string>;
var
  i:integer;
begin
  setlength(Result,0);
  for i := 0 to count-1 do
    Result[i]:=CastToString(Items[i]);
end;

{ TMyObjectList<T> }

function TMyObjectList<T>.CastToString(const Value: T): string;
begin
  result:=TMyObject(T).Name;
end;

end.

当我使用以下代码实现此代码时:

var
  MyList:TMyList<string>;
  AList1:Tarray<string>;

begin
  MyList:=TMyList<string>.create;
  MyList.Add('Name1');
  MyList.Add('Name1');
  Alist1:=MyList.MakeArray;
end;

在调用CastToString函数并尝试返回结果时,我在MakeArray调用期间继续获取AV。当我在同一点调用TMYObjectList时也会发生同样的情况。

我不确定我在这里使用仿制药是否有效或适合这种情况,如果没有,是否有更好的方法来做到这一点?我也在使用匿名方法,但不知道如何解决这个问题。

1 个答案:

答案 0 :(得分:8)

你的第一个问题在于:

function TMyList<T>.MakeArray: TArray<string>;
var
  i:integer;
begin
  setlength(Result,0); // <--- oops
  for i := 0 to count-1 do
    Result[i]:=CastToString(Items[i]);
end;

那应该是

SetLength(Result, Count);

然后考虑这个功能:

function TMyList<T>.GenericAsString(const Value): string;
begin
  Result := String(Value);
end;

您不能只将一个任意变量强制转换为字符串,并希望它能够正常工作。碰巧在你的代码中你只在Value是一个字符串时调用这个函数,但这不是一个好方法。您最好删除GenericAsString并将CastToString写为:

function TMyList<T>.CastToString(const Value: T): string;
begin
  Result := TValue.From<T>(Value).ToString;
end;

然而,在我看来,即便如此,也有可疑效用。

这段代码也错了:

function TMyObjectList<T>.CastToString(const Value: T): string;
begin
  result := TMyObject(T).Name;
end;

请记住,T是一种类型。您正在将类型转换为实例。总是失败。

你会这样写:

function TMyObjectList<T>.CastToString(const Value: T): string;
begin
  result := Value.Name;
end;

很难建议你如何继续。我不认为列表类实现获取其成员之一的字符串表示的能力是有意义的。但究竟应该在何处以及如何实现该功能取决于您的总体要求。我们根本看不到。