Mittwoch, 28. Februar 2018

PantherDI - Part 8: Progress-Update

This blogpost does not come with a released version. Instead I just want to give an update about the progress I made and where I still want to go before the release.

PRISM integration

The first and big change was the PRISM integration library which I decided to create as a separate repository that uses PantherDI as NuGet-Package.
While implementing this, I noticed that I needed to register some types only when the user of PantherDI hadn't already registered implementations for them.
The container (or container builder) does not have any support for this and I didn't want to give the PRISM integration library any control over PantherDI that a normal developer wouldn't have.
Thus I started my first approach of registering a type as a fallback (meaning it'll only be used if no type is already registered).
The idea was to create a container which only contains the fallback types and add this to the original container in a way that it's only used if the original container can't find anything.
Thus I started working on the general topic of adding containers to new containers and came up with three ways this could be done:

  • Adding a container as a resolver
  • Adding the providers of a container as factories
  • Creating child containers (which can access their parents content but not otherwise)

Nested Containers

Adding a container as resolver

This part was rather easy at first:
To add a container as resolver, I made it implement IResolver and implemented the Resolve method to simply call on the knowledge base and its resolvers to do the job.
I then refactored this, so a container needs to explicitely converted to a resolver using the AsResolver method.

Adding the providers of a container as factories

To do this I needed to create some code that creates a catalog from a container by iterating through all its resolvers and converting their content to registrations.
Since there are two resolver types that directly contain registrations and two types that contain more resolvers, I made this a depth-first-search through all resolvers.
For now only the knowledge base and the unconverted registrations in a RegistrationConverter can be converted. All resolvers implementing IEnumerable<IResolver> will be recursively processed.

Creating child containers

To create a child container in runtime I plan to make the interface IContainerBuilder resolvable.
When resolved, the container builder will build children of the container that resolved it.
That means that the new container has full access to the content of its parent, but the parent container is unable to resolve the content of its child.

This is added because normally the content of a container is immutable once it's been created.
If a container is disposed however, it will also dispose all of its children.

All singletons created will be part of the container that created them.
So child containers can not (yet) be used to indicate lifetime scopes.
Lifetime scoping is a feature planned for the future however.

Fallback registrations

However this does not solve the original problem of registering types as fallbacks for when no other registration exists.
I'm pondering two options right now - and will most likely add both:

  • Adding optional priorities to catalogs, registrations and factories
    Only the providers with the highest priority will be used, others will be ignored. A priority on a node deeper in the registration tree overrides the value it inherits from its parents. No priority means highest priority.
  • Making it possible to specify fallback catalogs.
    This would be implemented by making the ContainerBuilder store a second List<Catalogs>.
    The factories from the second list will only be considered for a contract if there isn't yet factory present for it.

Then the PRISM integration library could be completed and a simple sample project created. The sample will grow and show how-tos for using PantherDI with PRISM.