I\'m trying to cast a returned base object to it\'s specific generic type. The code below should work I think but generates an internal compiler error, is there another way to
The answer above from Andreas is brilliant. It's really helped my use of generics in Delphi. Please then forgive me Andreas as I wonder if DynamicCast is a little complicated. Please correct me if I'm wrong but the following should be a little more concise, safe, fast (no string comparisons) and still as functional.
Really all I've done is use the class constraint on the DynamicCast type params to allow the compiler to do a bit of work (as the original will always except with non-class parameters) and then use the TObject.InheritsFrom function to check for type compatibility.
I've also found the idea of a TryCast function quite useful (it's a common task for me anyway!)
This is of course unless I've missed the point somewhere in trawling the class parents for matching names... which IMHO is a little dangerous given that type names may match for non compatible classes in different scopes.
Anyway, here's my code (works for Delphi XE3... D2009 compatible version of TryCast follows after).
type
TTypeCast = class
public
// ReinterpretCast does a hard type cast
class function ReinterpretCast(const Value): ReturnT;
// StaticCast does a hard type cast but requires an input type
class function StaticCast(const Value: T): ReturnT;
// Attempt a dynamic cast, returning True if successful
class function TryCast(const Value: T; out Return: ReturnT): Boolean;
// DynamicCast is like the as-operator. It checks if the object can be typecasted
class function DynamicCast(const Value: T): ReturnT;
end;
implementation
uses
System.SysUtils;
class function TTypeCast.ReinterpretCast(const Value): ReturnT;
begin
Result := ReturnT(Value);
end;
class function TTypeCast.StaticCast(const Value: T): ReturnT;
begin
Result := ReinterpretCast(Value);
end;
class function TTypeCast.TryCast(const Value: T; out Return: ReturnT): Boolean;
begin
Result := (not Assigned(Value)) or Value.InheritsFrom(ReturnT);
if Result then
Return := ReinterpretCast(Value);
end;
class function TTypeCast.DynamicCast(const Value: T): ReturnT;
begin
if not TryCast(Value, Result) then
//Value will definately be assigned is TryCast returns false
raise EInvalidCast.CreateFmt('Invalid class typecast from %s(%s) to %s',
[T.ClassName, Value.ClassName, ReturnT.ClassName]);
end;
As promised the D2009 version (needs some small effort to get to the class of ReturnT).
class function TTypeCast.TryCast(const Value: T; out Return: ReturnT): Boolean;
var
LReturnTypeInfo: PTypeInfo;
LReturnClass: TClass;
begin
Result := True;
if not Assigned(Value) then
Return := Default(ReturnT)
else
begin
LReturnTypeInfo := TypeInfo(ReturnT);
LReturnClass := GetTypeData(LReturnTypeInfo).ClassType;
if Value.InheritsFrom(LReturnClass) then
Return := ReinterpretCast(Value)
else
Result := False;
end;
end;