我有一个需要返回对象的方法。当然,只有T
是 对象才有意义:
function TGrobber<T>.Swipe: TObject;
var
current: T;
begin
{
If generic T is not an object, then there's nothing we can return
But we'll do the caller a favor and not crash horribly.
}
if PTypeInfo(TypeInfo(T))^.Kind <> tkClass then
begin
Result := nil;
Exit;
end;
//We *are* an object, return the object that we are.
current := Self.SwipeT;
Result := TObject(current); <--E2089 invalid class typecast
end;
如果T
不是对象(例如Integer
,String
或OleVariant
),那么它将返回nil
,并且不会崩溃
如果我们是一个对象(例如TCustomer
,TPatron
,TSalesOrder
,TShape
),那么我们可以很好地返回该对象。
我不想混淆这个问题;但如果你看IEnumerable
,你会看到实际发生的事情。
我会让TLama复制/粘贴答案以获得他的信任:
function TGrobber<T>.Swipe: TObject;
var
current: T;
v: TValue;
begin
current := Self.SwipeT;
v := TValue.From<T>(current);
{
If generic T is not an object, then there's nothing we can return
But we'll do the caller a favor and not crash horribly.
}
if not v.IsObject then
begin
Result := nil;
Exit;
end;
Result := v.AsObject;
end;
答案 0 :(得分:2)
我看到两个主要选择。如果泛型类型必须是类类型,并且在编译时知道,则应对类型应用约束:
type
TGrobber<T: class> = class
....
end;
或者,如果类型必须从特定类派生,则可以如下指定该约束:
type
TGrobber<T: TMyObject> = class
....
end;
一旦应用了约束,您就可以直接进行分配。
Result := current;
这是可能的,因为编译器对您的泛型类型强制执行约束。因此知道赋值对所有可能的实例都有效。
我会评论一个泛型类使函数返回TObject
似乎很奇怪。为什么函数不返回T
?
如果你不能约束那么简单的指针类型转换是最干净的方法:
Result := PObject(@current)^;
显然,您需要检查T
是否为类型,您已经证明已经掌握的代码。
对于它的价值,自Delphi XE7以来,使用System.GetTypeKind
检查类型的类型更简单:
if GetTypeKind(T) = tkClass then
Result := PObject(@current)^
else
Result := nil;
答案 1 :(得分:0)
是的,可以通过TValue完成,但这不是正确的方法。我相信让编译器验证它是TObject(或后代)更好。
unit GrobberU;
interface
type
TGrobber<T : Class> = class
public
function Swipe: TObject;
end;
implementation
{ TGrobber<T> }
function TGrobber<T>.Swipe: TObject;
begin
Result := T;
end;
end.
然后你可以测试它:
procedure TForm37.FormCreate(Sender: TObject);
var
Grobber1 : TGrobber<TEdit>;
Grobber2 : TGrobber<Integer>; <-- Does not compile
begin
end;