I have a method that needs to return an object. Of course, it only makes sense if the T
is an object:
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;
If T
is not an object (e.g. an Integer
, String
, or OleVariant
), then it will return nil
, and not crash horribly.
If we are an object (e.g. TCustomer
, TPatron
, TSalesOrder
, TShape
), then we can return the object just fine.
I didn't want to confuse the issue; but if you look at IEnumerable
, you'll see what is actually going on.
I'll let TLama copy/paste the answer to get his credit:
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;
I see two main options. If the generic type must be a class type, and this is know at compile time, you should apply a constraint to the type:
type
TGrobber<T: class> = class
....
end;
Or if the type must derive from a specific class then that constraint can be specifies like so:
type
TGrobber<T: TMyObject> = class
....
end;
Once the constraint is applied then direct assignment is all you need.
Result := current;
This becomes possible because the compiler enforces the constraint on your generic type. And so knows that the assignment is valid for all possible instantiations.
I would comment that it seems odd for a generic class to have a function returning TObject
. Why doesn't your function return T
?
If you cannot constrain then a simple pointer type cast is the cleanest approach:
Result := PObject(@current)^;
Obviously you need to check that T
is a class type, code for which you have already demonstrated mastery.
For what it is worth, since Delphi XE7 it is simpler to check the kind of a type using System.GetTypeKind
:
if GetTypeKind(T) = tkClass then
Result := PObject(@current)^
else
Result := nil;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With