I am faced with the problem of properly object instantiating from the type resolved by a Spring4D framework container.
I have a class:
type
TSurvey = class ( TInterfacedObject, ISurvey )
private
_id : Integer;
_organization : IOrganization;
function GetId () : Integer;
procedure SetId ( const value : Integer );
function GetOrganization () : IOrganization;
procedure SetOrganization ( const value : IOrganization);
public
property Id : Integer read GetId write SetId;
property Organization: IOrganization read GetOrganization write SetOrganization;
end;
...
initialization
GlobalContainer.RegisterType<TSurvey>.Implements<ISurvey>.InjectField ( '_organization' );
...
I use the GlobalContainer to instantiate an object:
survey := GlobalContainer.Resolve<ISurvey>;
survey.Organization.Id := 5;
and everything is alright and works perfectly.
Now I want to create a descendant class for TSurvey:
type
TFieldSurvey = class ( TSurvey )
...
end;
And the question is how to correct instantiate an object for TFieldSurvey class?
If I use Create (), then I get an exception:
fieldSurvey := TFieldSurvey.Create ();
fieldSurvey.Organization.Id := 5 <- exception is here
Do I have to explicitly call the constructor for Organization field in TFieldSurvey constructor, or there is another way? For example, using GlobalContainer?
Thanks in advance.
The Injection will only work when you create your object through the Container, not by directly calling the constructor on your object. So you would need to register TFieldSurvey
with GlobalContainer
and then call Resolve
to get your object.
Register:
GlobalContainer.RegisterType<TSurvey>.Implements<ISurvey>('SPRING_SURVEY').InjectField ( '_organization' );
GlobalContainer.RegisterType<TFieldSurvey>.Implements<ISurvey>('SPRING_FIELD_SURVEY').InjectField ( '_organization' );
Then to obtain an instance:
GlobalContainer.Resolve<ISurvey>('SPRING_FIELD_SURVEY')
I added the names of 'SPRING_SURVEY' and 'SPRING_FIELD_SURVEY' since they both implement ISurvey
and this lets you choose which class instance you want otherwise you end up with the last implementation registered for that interface. If TFieldSurvey
is going to implement its own interface (eg IFieldSurvey
) you could do away with the names and then typecast back to ISurvey
if needed.
You could always use the [Inject]
attribute too on _organization field rather than using .InjectField (after adding Global.Container.Common
to your uses):
TSurvey = class ( TInterfacedObject, ISurvey )
private
_id : Integer;
[Inject]
_organization : IOrganization;
function GetId () : Integer;
procedure SetId ( const value : Integer );
function GetOrganization () : IOrganization;
procedure SetOrganization ( const value : IOrganization);
public
property Id : Integer read GetId write SetId;
property Organization: IOrganization read GetOrganization write SetOrganization;
end;
and your registration would be:
GlobalContainer.RegisterType<TSurvey>.Implements<ISurvey>('SPRING_SURVEY');
GlobalContainer.RegisterType<TFieldSurvey>.Implements<ISurvey>('SPRING_FIELD_SURVEY');