La respuesta anterior de Andreas es brillante. Realmente ayudó mi uso de los genéricos en Delphi. Por favor, perdónenme, Andreas, ya que me pregunto si DynamicCast es un poco complicado. Por favor corrígeme si me equivoco, pero lo siguiente debe ser un poco más conciso, seguro, rápido (sin comparaciones de cadenas) y sigue siendo funcional.
Realmente todo lo que he hecho es utilizar la restricción de clase en los params de tipo DynamicCast para permitir que el compilador trabaje un poco (como el original siempre excepto con parámetros que no sean de clase) y luego usar TObject.InheritsFrom función para verificar la compatibilidad del tipo.
También he encontrado la idea de una función TryCast bastante útil (que es una tarea común para mí de todos modos!)
Esto es, por supuesto, a menos que me he perdido el punto en algún lugar de la pesca de arrastre de los padres de la clase para hacer coincidir nombres ... que en mi humilde opinión es un poco peligroso dado que los nombres de tipo pueden coincidir con las clases no compatibles en diferentes ámbitos.
De todos modos, aquí está mi código (a continuación, funciona la versión compatible con Delphi XE3 ... D2009 de TryCast).
type
TTypeCast = class
public
// ReinterpretCast does a hard type cast
class function ReinterpretCast<ReturnT>(const Value): ReturnT;
// StaticCast does a hard type cast but requires an input type
class function StaticCast<T, ReturnT>(const Value: T): ReturnT;
// Attempt a dynamic cast, returning True if successful
class function TryCast<T, ReturnT: class>(const Value: T; out Return: ReturnT): Boolean;
// DynamicCast is like the as-operator. It checks if the object can be typecasted
class function DynamicCast<T, ReturnT: class>(const Value: T): ReturnT;
end;
implementation
uses
System.SysUtils;
class function TTypeCast.ReinterpretCast<ReturnT>(const Value): ReturnT;
begin
Result := ReturnT(Value);
end;
class function TTypeCast.StaticCast<T, ReturnT>(const Value: T): ReturnT;
begin
Result := ReinterpretCast<ReturnT>(Value);
end;
class function TTypeCast.TryCast<T, ReturnT>(const Value: T; out Return: ReturnT): Boolean;
begin
Result := (not Assigned(Value)) or Value.InheritsFrom(ReturnT);
if Result then
Return := ReinterpretCast<ReturnT>(Value);
end;
class function TTypeCast.DynamicCast<T, ReturnT>(const Value: T): ReturnT;
begin
if not TryCast<T, ReturnT>(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;
Según lo prometido, la versión D2009 (necesita un pequeño esfuerzo para llegar a la clase de ReturnT).
class function TTypeCast.TryCast<T, ReturnT>(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<ReturnT>(Value)
else
Result := False;
end;
end;
Lástima que no puedo marcar esto como una respuesta favorita ... – gabr
¡esto es mejor! – kabstergo