Delphi通用列表到字符串

Delphi通用列表到字符串,delphi,generics,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;

我看到的是一个通用列表,它可以基于特定字段写入任何对象的字符串数组。基本列表将有许多子体。声明的代码如下所示,编译良好:

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.
单元测试列表;
接口
使用
类、System.Rtti、System.Generics.Collections、System.SysUtils;
类型
TMakeString=对函数的引用(常量输入:T):字符串;
TMyList=class(TList)
受保护的
函数GenericAsString(常量值):字符串;
函数CastToString(常量值:T):字符串;事实上的
公众的
函数MakeArray:TArray;
结束;
TMyObject=类(ToObject)
私有的
fname:字符串;
公众的
属性名称:字符串读取fname写入fname;
结束;
TMyObjectList=类(TMyList)
受保护的
函数CastToString(常量值:T):字符串;推翻
结束;
实施
{TMyList}
函数TMyList.CastToString(常量值:T):字符串;
开始
结果:='';
如果TypeInfo(T)=TypeInfo(字符串),则
结果:=通用字符串(值);
结束;
函数TMyList.GenericAsString(常量值):字符串;
开始
结果:=字符串(值);
结束;
函数TMyList.MakeArray:TArray;
变量
i:整数;
开始
setlength(结果为0);
对于i:=0到count-1 do
结果[i]:=CastToString(项目[i]);
结束;
{TMyObjectList}
函数TMyObjectList.CastToString(常量值:T):字符串;
开始
结果:=TMyObject(T).Name;
结束;
结束。
当我使用以下方法实现此代码时:

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

begin
  MyList:=TMyList<string>.create;
  MyList.Add('Name1');
  MyList.Add('Name1');
  Alist1:=MyList.MakeArray;
end;
var
MyList:TMyList;
AList1:Tarray;
开始
MyList:=TMyList.create;
MyList.Add('Name1');
MyList.Add('Name1');
Alist1:=MyList.MakeArray;
结束;
在MakeArray调用过程中,当它调用CastToString函数并尝试返回结果时,我不断得到一个AV。当我在同一点调用TMYObjectList时,也会发生同样的情况


我不确定我在这里使用泛型是否有效或适合这种情况,如果不是,还有更好的方法吗?我也曾尝试过使用匿名方法,但不确定该如何操作。

您的第一个问题在于:

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;

然后考虑这个函数:

function TMyList<T>.GenericAsString(const Value): string;
begin
  Result := String(Value);
end;
然而,在我看来,即使这样也有可疑的效用

这个代码也是错误的:

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

很难就如何进行向你提供建议。我认为list类实现获取其成员的字符串表示的功能是没有意义的。但是,该功能应该在何处以及如何实现在很大程度上取决于您的总体需求。这是我们无法看到的。

如果您使用的是D2009+,那么所有的
TObject
s都有一个虚拟的
.ToString
方法。在你的类中重写并实现它,你的工作就会变得简单得多…实际上,你在使用泛型,所以你必须使用D2009+@J。。。是的,如果他可以se
ToString
,那么他可以这样做:也就是说,对于您认为来自其他源(如VCL类)的类,您不能从外部实现访问者。无论什么
.ToString
,它们都是现成的-很可能是您唯一可以使用的东西。类外
TMakeString
即使看起来不那么简洁和优雅,也会打破这种依赖关系。我记得现在在源代码中看到了这一点,并同意这是一种有用的方法,谢谢提醒。另一方面,你的类助手示例不会编译!(XE8)。所有其他示例都在非泛型类型上显示了这种方法。在D2009上也有其他帖子表明这是不可能的,只是对于实例化的类型来说,这有点违背了目的。最好的方法可能是继承方法。感谢您指出明显的错误。我发现自己不止一次地使用这个特性,主要是在诊断中,因此我认为应该将它包括在基类中。
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;
function TMyObjectList<T>.CastToString(const Value: T): string;
begin
  result := Value.Name;
end;