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