Damit geht das
Delphi-Quellcode:
class function GlobalContainer.GetClass<T> : T;
var
LGUID : TGUID;
LClass : TClass;
LObj : TObject;
begin
LGUID := GetTypeData( TypeInfo( T ) ).Guid;
if _ClassDict.ContainsKey( LGUID ) then
begin
LClass := _ClassDict.Items[LGUID];
LObj := LClass.Create;
Supports( LObj, LGUID, Result );
end;
end;
Leider geht das so nicht. Deshalb gibt es in Spring4d auch relativ komplexe Logik, um den "best matching" Konstruktor zu finden.
Es ist nämlich nicht immer richtig den Parameterlosen Standardkonstruktor aufzurufen, da er eigentlich versteckt wurde (z.B. bei TComponent)
Über deine Logik würde zwar der richtige Speicher allokiert aber niemals die ganzen Dinge aus dem
Create(AOwner: TComponent)
durchlaufen. Auch Spring4d ist nicht komplett wasserdicht, da die
RTTI keine Möglichkeit bietet zu ermitteln, ob eine Methode überschrieben oder verdeckt wurde. Auch der constructor Constraint bei generics leidet unter dieser Macke, so dass ein
T.Create
ziemlich böse Folgen haben kann.
Aktueller Source von Spring4d liegt übrigens hier:
https://bitbucket.org/sglienke/spring4d (das Google Code Repo wird nicht mehr aktualisiert)
Mein Vorschlag wäre übrigens, nicht Interface/Klasse als Kombination zu registrieren, sondern Interface/Factory.
Somit würde aus deinem Dictionary ein
TDictionary<string, TFunc<IInterface>>
.
Die RegisterClass Methode würd ich dann so schreiben (nicht Compiler checked):
Delphi-Quellcode:
class procedure GlobalContainer.RegisterClass<TInterface: IInterface, TRegClass:
class,
constructor>(
const Name :
string );
var
LGUID : TGUID;
LKey :
string;
begin
// hier aufpassen, kann auch keine guid haben, dann sollte man hier einen Fehler werfen, denn das resolven wird nicht ohne funktionieren
// ebenfalls sollte man checken, ob die Klasse, das Interface überhaupt supported
LGUID := GetTypeData( TypeInfo( TInterface ) ).Guid;
LKey := LGUID.ToString +
Name.ToUpper;
_ClassDict.AddOrSetValue( LKey,
function: IInterface
var
obj: TObject;
begin
// wie gesagt, hier aufpassen, kann sein, dass das den falschen Konstruktor aufruft, das fängt auch der constructor Contraint nicht korrekt ab
obj := TRegClass.Create;
// kein if notwendig, wenn oben geschaut wurde, ob das hier auch funktioniert
Supports(obj, LGUID, Result);
end);
end;
Das hat nun den Vorteil, dass du auch eine
RegisterClass<IMyIntf>(function: IMyIntf begin Result := GetMyIntfFromSomewhere() end)
schreiben kannst und nicht nur auf Zuordnung von Interface zu Klasse beschränkt bist.