我正在查看一个通用列表,该列表可以根据特定字段写入任何对象的字符串数组。基本列表将包含许多后代。声明的代码如下所示,编译良好:
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时也会发生同样的情况。
我不确定我在这里使用仿制药是否有效或适合这种情况,如果没有,是否有更好的方法来做到这一点?我也在使用匿名方法,但不知道如何解决这个问题。
答案 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;
很难建议你如何继续。我不认为列表类实现获取其成员之一的字符串表示的能力是有意义的。但究竟应该在何处以及如何实现该功能取决于您的总体要求。我们根本看不到。