Creando un IoC Delphi. Cómo deshabilitar el enlazador de Delphi para eliminar clases no utilizadas
linker inversion-of-control (2)
Agregue la directiva {$STRONGLINKTYPES ON}
al .dpr. Entonces esos tipos deberían ser incluidos. Pero definitivamente hará volar tu aplicación, ya que no está disponible para una sola clase.
Creé un IoC en Delphi con la capacidad de registrar automáticamente cualquier clase que tenga un IocSingletonAttribute.
El registro automático se parece a lo siguiente.
procedure TIocContainer.AutoRegister;
var
ctx: TRttiContext;
rType: TRttiType;
attr: TCustomAttribute;
&Type: PTypeInfo;
begin
ctx := TRttiContext.Create;
for rType in ctx.GetTypes do
Begin
for attr in rType.GetAttributes do
Begin
if TypeInfo(IocSingletonAttribute) = attr.ClassInfo then
Begin
&Type := IocSingletonAttribute(attr).&Type;
RegisterType(&Type, rType.Handle, True);
End;
End;
End;
end;
Luego creo una implementación y agrego IocSingletonAttribute a ella. Se parece a esto
[IocSingleton(TypeInfo(IIocSingleton))]
TIocSingleton = class(TInterfacedObject, IIocSingleton)
procedure DoSomeWork;
end;
Entonces, ahora al código real del programa. Si escribo el código a continuación, el IoC no funciona. El procedimiento AutoRegister no recogió TIocSingleton.
var
Ioc: TIocContainer;
Singleton: IIocSingleton;
begin
Ioc := TIocContainer.Create;
try
Ioc.AutoRegister;
Singleton := Ioc.Resolve<IIocSingleton>();
Singleton.DoSomeWork;
finally
Ioc.Free;
end;
end.
Pero si escribo el código a continuación, todo funciona como se espera. Observe cómo he declarado la clase TIocSingleton y lo he usado.
var
Ioc: TIocContainer;
Singleton: IIocSingleton;
ASingleton: TIocSingleton;
begin
Ioc := TIocContainer.Create;
ASingleton := TIocSingleton.Create;
try
Ioc.AutoRegister;
Singleton := Ioc.Resolve<IIocSingleton>();
Singleton.DoSomeWork;
finally
Singleton.Free;
Ioc.Free;
end;
end.
Por lo tanto, basado en esto, supongo que el enlazador de compilador de Delphi está eliminando TIocSingleton en el primer ejemplo porque nunca fue utilizado explícitamente en ninguna parte de la aplicación. Entonces mi pregunta es, ¿es posible cambiar la característica del ''eliminar código no utilizado'' del compilador para una cierta clase? O si mi problema no es el enlazador, ¿alguien puede arrojar luz sobre por qué funciona el segundo ejemplo pero no el primero?
Gracias a Sebastián Z responde por y para Agustín Ortu comenta. Ambas respuestas me llevaron a una solución final. No es posible utilizar STRONGLINKTYPES para una sola clase, desafortunadamente, y la clase debe ser referenciada de alguna manera. Decidí no utilizar la sugerencia exacta de Augstin Ortu pero usé el concepto.
En la unidad donde IoC está definido, publico el siguiente procedimiento vacío.
procedure IocReference(AClass: TClass);
implementation
procedure IocReference(AClass: TClass);
begin
end;
Y en la clase que crea una clase para ser utilizada por IoC agrego lo siguiente
initialization
IocReference(TIocSingleton);
end.
La razón para usar un procedimiento para evitar que el vinculador elimine el código en lugar de simplemente llamar a una función de clase, por ejemplo (TIocSingleton.ClassName) es que proporciona una mejor información. Si otro programador lee el código, pueden adivinar por qué esa línea está allí.