Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a Delphi IoC. How to disable Delphi's linker from removing unused classes

I've created a IoC in delphi with the ability to automatically register any classes that have a IocSingletonAttribute to it.

The AutoRegister looks like the following.

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;

I then create a implementation and add the IocSingletonAttribute to it. It looks like this

[IocSingleton(TypeInfo(IIocSingleton))]
TIocSingleton = class(TInterfacedObject, IIocSingleton)
  procedure DoSomeWork;
end;

So, now to the actual code of the program. If I write the code below the IoC doesn't work. The AutoRegister procedure didn't pick up TIocSingleton.

var
  Ioc: TIocContainer;  
  Singleton: IIocSingleton;  
begin  
  Ioc := TIocContainer.Create;
  try    
    Ioc.AutoRegister;
    Singleton := Ioc.Resolve<IIocSingleton>();
    Singleton.DoSomeWork;
  finally 
    Ioc.Free;
  end;
end.

But if I write the code below instead everything works as expected. Notice how i have declared TIocSingleton class and have used it.

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.

So based on this, I'm assuming Delphi's compiler linker is removing TIocSingleton in the first example because it was never explicitly used in any part of the application. So my question is, is it possible to turn of the compiler's 'remove unused code' feature for a certain class ? Or if my problem isn't the linker, can anyone shed light on why the second example works but not the first ?

like image 580
Coolio Avatar asked Feb 05 '17 16:02

Coolio


2 Answers

Add the {$STRONGLINKTYPES ON} directive to the .dpr. Then those types should be included. But it will definitely blow up your application, as it is not available for a single class.

like image 62
Sebastian Z Avatar answered Oct 23 '22 03:10

Sebastian Z


Thanks to Sebastian Z answer for and for Agustin Ortu comment. Both their responses got me to a final solution. It's not possible to use STRONGLINKTYPES for just one class, unfortunately, and the class needs to be referenced somehow. I decided not to use Augstin Ortu exact suggestion but I did use the concept.

In the unit where IoC is defined I output the following empty procedure.

procedure IocReference(AClass: TClass);

implementation

procedure IocReference(AClass: TClass);
begin
end; 

And in the class that creates a class to be used by IoC I add the following

initialization
  IocReference(TIocSingleton);
end.

The reason to use a procedure to keep the linker from removing the code instead of just calling a class function, eg (TIocSingleton.ClassName) is that it provided better information. If another programmer reads the code they can take a good guess as to why that line is there.

like image 1
Coolio Avatar answered Oct 23 '22 03:10

Coolio