Open Simmay93 opened 3 years ago
If InnterClass
is determined by TypeEnum
, it should be provided in a way other than injecting it.
You can use registerFactory()`` to generate the
InnerClassfrom the
TypeEnum` at the time of injection.
Example:
fruit::Component<std::function<std::unique_ptr<IOuterClass>(TypeEnum)> getOuterClassComponent()
{
return fruit::createComponent()
.bind<IOuterClass, OuterClass>()
.registerFactory<std::unique_ptr<OuterClass>(TypeEnum)>(
[](TypeEnum type) {
IClass* innerClass = getInnerClassComponent(type);
return std::make_unique<OuterClass>(type, innerClass);
});
}
// Usage
std::function<std::unique_ptr<IOuterClass>(TypeEnum)> iOuterClassFactory(injector);
std::unique_ptr<IOuterClass> outerClass = iOuterClassFactory(TypeEnum::A);
Look "Factories and assisted injection" section: https://github.com/google/fruit/wiki/quick-reference#factories-and-assisted-injection
That looks pretty nice. Thanks for the fast answer.
I have one more question:
The function getInnerClassComponent()
is also a fruit::Component. How can I create the instance from this or do I have to implement it without fruit?
If IClass
is allowed to create a different instance each time the factory function is called (not a singleton), then getInnerClassComponent()
should be a factory fruit component.
You should be able to get that factory function by using fruit::Assisted
in getOuterClassComponent()
.
Example:
fruit::Component<std::function<std::unique_ptr<IOuterClass>(TypeEnum)> getOuterClassComponent()
{
return fruit::createComponent()
.bind<IOuterClass, OuterClass>()
.registerFactory<
std::unique_ptr<OuterClass>(
TypeEnum,
fruit::Assisted<std::function<std::unique_ptr<IClass>(TypeEnum)>>&)>(
[](TypeEnum type,
std::function<std::unique_ptr<IClass>(TypeEnum)>& innerClassFactory) {
std::unique_ptr<IClass> innerClass = getInnerClassComponent(type);
return std::make_unique<OuterClass>(type, std::move(innerClass));
});
}
If you want to make IClass
a singleton, you can use Annotated Injection to add a mark to identify the instance of IClass
to fruit.
Wiki: https://github.com/google/fruit/wiki/quick-reference#annotated-injection
+1 to the suggestion to use annotated injection, I think that's a good fit here. You might want to use an annotation type templated on the enum:
enum TypeEnum { ... };
template <TypeEnum X>
struct TypeEnumAnnotation {};
And then using fruit::Annotated<TypeEnumAnnotation<SOME_VALUE>, IClass>
.
If you want an OuterClass instance for each enum value, you could templatize that on TypeEnum too (templatizing getOuterClassComponent too to match).
Assisted injection is more for cases where you want to supply the enum value outside of Fruit, after injection; while here it seems that you know the value from the get*Component stage already so you can pass it there and Fruit can handle the IClass instances as singletons for you (1 per enum value).
P.S. @tt4g : thanks for replying, very appreciated (as always)!
Thank you both for your suggestions but hardly I still don't get it.
Maybe I explain my code a little bit more.
OuterClass is constructed several times during runtime. The concrete implementations of IClass can be singletons. The type of the singleton is only known at construction time.
As far as I got the documentation and your help I need a factory for OuterClass. That factory needs the type due to the construction time constraint. But inside the factory function I have to create the concrete class without any fruit "magic". How can I connect this to the singleton with the correct type?
OuterClass is constructed several times during runtime.
Is this 1 per value of the enum, or are there enum values for which you want to construct multiple instances of that with the same enum value? Or is it ok either way?
Is there a single enum value that you use (and it's just determined later) or do you want to comstruct OuterClass instances with different enum values from the same injector?
The type of the singleton is only known at construction time.
Can you expand on this? Is that determined from the enum value alone or also other data?
OuterClass is constructed several times with several enum values (n-m relation). There are 3 enum values. So there are 3 different "types" of IClass. These can implemented as singleton using fruit::Component.
I'd like to construct OuterClass instances from the same injector (if possible). The enum value is known at construction time of the OuterClass implementation. It is just determined from the enum value. It is given into the constructor and depending on the enum value we need the specific "type" of IClass.
Thats why I did the approach with the ASSISTED argument and the factory approach but I miss the point how to bring this together with the fruit::Component of IClass
@Simmay93 I create a small project: https://github.com/tt4g/fruit-issue-130/tree/main
This project creates a singleton instance of IClass
and OuterClass
for each TypeEnum
.
It may help you solve your problem by browsing the source.
Hi there,
I have the following problem: I have a class with an assisted parameter and a component in the constructor. The assisted variable is needed for the construction of the component. How can I solve this problem. I did not find a straight forward solution in the wiki.
for the innerClass I have a method which returns an actual class according to the type:
the factory looks like this: