ipjohnson / Grace

Grace is a feature rich dependency injection container library
MIT License
336 stars 33 forks source link

IEnumerable<Scoped<T>> doesn't work as expected #230

Closed jods4 closed 4 years ago

jods4 commented 4 years ago

Let's say your container contains many IFrob exports, let's call them Frob1 and Frob2.

If you want all of them you can Locate<IEnumerable<IFrob>>(), which will give you Frob1, Frob2.

Maybe you want to be able to spawn new frobs and locating IEnumerable<Func<IFrob>> does give you two factories. If you .Select(f => f()) then you end up with Frob1, Frob2, as expected.

Now let's say that in addition to that you want each factory to resolve in a new scope. You locate IEnumerable<Func<Scoped<IFrob>>> which returns 2 factories as expected. But (ignoring Dispose for now) if you look at .Select(f => f().Instance) then you'll notice every scoped instance resolves to the same IFrob: Frob2, Frob2 (based on priority, etc.)

It seems to me that Scoped "forgets" what specific IFrob it was supposed to be and just performs a plain Locate<IFrob> again, which is not what I want. This makes Scoped<IFrob> useless/incompatible with IEnumerable. In fact, just locating IEnumerable<Scoped<IFrob>> returns Frob2, Frob2.

This is a simplified test case. My full code was: IEnumerable<Meta<Func<string, Scoped<T>>>> because on top of that I wanted per-IFrob meta information (before invoking the factory; meta infos seem to be right) and named scopes (seems to work ok as well).

ipjohnson commented 4 years ago

I see what you mean it's really not a robust implementation. I'll need to think about it a bit to see what's the best solution for this.

jods4 commented 4 years ago

Can you advise a workaround in the meantime? I'm having a hard time figuring out how to do this any other way.

I want to be able:

ipjohnson commented 4 years ago

Sorry meant to reply this weekend. There isn't a good work around for the moment but I do think I should be able to find some time this weekend to fix it properly and do a beta release.

jods4 commented 4 years ago

Thanks.

FWIW I managed to workaround the problem but it's very convoluted. I used named exports instead metadata; then i'm casting the IExportLocatorScope to DependencyInjectionContainer so that I can use StrategyCollectionContainer.GetActivationStrategyCollection to enumerate all keys and metadata related to an interface; finally I can create a lifetime scope and Locate the interface and key previously gathered to find the instance that I want.

It's ugly :( but it works for now.

ipjohnson commented 4 years ago

I have one more issue I need to address before I can do a beta release but you can test the fix in the nightly nuget feed

https://ci.appveyor.com/nuget/grace-master

jods4 commented 4 years ago

Thanks! Switching feeds is a bit complicated (don't ask) but if you do a prerelease on Nuget I can test. Otherwise I can wait a little bit more.

ipjohnson commented 4 years ago

I've released a new version 7.1.0-beta

jods4 commented 4 years ago

Thanks, I referenced the 7.1 beta and it works now! ❤️