Odpowiedź wyżej od Andreas jest genialny. To naprawdę pomogło mi w używaniu leków generycznych w Delphi. Proszę, wybacz mi Andreas, gdy zastanawiam się, czy DynamicCast jest trochę skomplikowany. Proszę mnie poprawić, jeśli się mylę, ale poniższe informacje powinny być trochę bardziej zwięzłe, bezpieczne, szybkie (bez porównań ciągów znaków) i nadal funkcjonalne.
Naprawdę wszystko, co zrobiłem, to użycie ograniczenia klasy w typach DynamicCast, aby umożliwić kompilatorowi wykonanie trochę pracy (ponieważ oryginał zawsze będzie wyjątkiem parametrów innych niż klasy), a następnie użyć TObject.InheritsFrom funkcja do sprawdzenia kompatybilności typów.
Ja również znaleźć ideę funkcji TryCast całkiem użytecznego (jest to wspólne zadanie dla mnie w każdym razie!)
Jest to oczywiście chyba Tęskniłam punkt gdzieś w trałowania rodziców klasy do dopasowania nazwy ... które IMHO jest trochę niebezpieczne, ponieważ nazwy typów mogą pasować do niekompatybilnych klas w różnych zakresach.
W każdym razie, oto mój kod (działa dla Delphi XE3 ... po TryCastzie zgodna z D2009).
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;
Zgodnie z obietnicą, wersja D2009 (potrzebuje trochę wysiłku, aby dostać się do klasy 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;
Szkoda, nie mogę oznaczyć tego jako ulubionej odpowiedzi ... – gabr
to jest coś więcej! – kabstergo