La risposta di cui sopra da Andreas è brillante. Ha davvero aiutato il mio uso di generici in Delphi. Per favore, perdonami, Andreas, perché mi chiedo se DynamicCast sia un po 'complicato. Per favore correggimi se sbaglio, ma quanto segue dovrebbe essere un po 'più conciso, sicuro, veloce (senza confronti tra stringhe) e comunque funzionale.
davvero tutto quello che ho fatto è utilizzare il vincolo di classe sui params di tipo dynamic_cast per consentire al compilatore di fare un po 'di lavoro (come l'originale sarà sempre se non con parametri non-classe) e quindi utilizzare il TObject.InheritsFrom funzione per verificare la compatibilità del tipo.
Ho anche trovato l'idea di una funzione molto utile TryCast (in ogni caso si tratta di un compito comune per me!)
Questo è, naturalmente, a meno che non ho perso il punto da qualche parte nella pesca a strascico i genitori della classe per la corrispondenza nomi ... che IMHO è un po 'pericoloso dato che i nomi dei tipi possono corrispondere per classi non compatibili in ambiti diversi.
In ogni caso, ecco il mio codice (funziona per Delphi XE3 ... segue la versione compatibile D2009 di 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;
Come promesso la versione D2009 (richiede un piccolo sforzo per raggiungere la classe di 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;
Peccato non posso contrassegnarlo come una risposta preferita ... – gabr
questo è più grande! – kabstergo