Skip to content
This repository has been archived by the owner on Dec 19, 2023. It is now read-only.

Behaviours/configuration/or what!? #45

Closed
LordZoltan opened this issue May 19, 2017 · 2 comments
Closed

Behaviours/configuration/or what!? #45

LordZoltan opened this issue May 19, 2017 · 2 comments
Assignees

Comments

@LordZoltan
Copy link
Member

LordZoltan commented May 19, 2017

Braindumps are just my way of sketching out stuff when I hit an impasse. Effectively they're just interior monologues. They might stop half way through, they might not make any sense. Why am I putting them up here instead of on Keep or Notes or whatever? Because why hide it?

Having started work on an options-style system (here and here - ignore the file names etc - nothing's final yet) I'm certain I'm close to a great way to offer consumers a fantastic way to configure options/rules for different types in the container; and for difference common IOC patterns.

The problem is that in 1.2 I also introduced behaviours which are ultimately a glorified set of startup registrations that get applied to any new instance of the target container types - e.g. TargetContainer or GenericTargetContainer - and container types (Container, OverridingContainer etc)

What are behaviours and options for?

ITargetContainerBehaviours:

  • Automatic enumerable resolving - registers a custom ITargetContainer for IEnumerable<>
  • Resolving IResolveContext - registers a target that simply returns the input context (via ICompiledTarget)

Container behaviours:

  • Set the default IMemberBindingBehaviour for ConstructorTarget
  • Set the compiler that is to be used

Overriding container:

  • Change the enumerable container to the OverridingEnumerableContainer which combines enumerables from the overriding container with one from the base.

What separates target behaviours from container behaviours? It's the difference between a registration that applies before targets are registered, or which apply only when a container starts resolving instances.

The IMemberBindingBehaviour is a grey area, it's actually used by ConstructorTarget, and requires an ICompileContext - but there's no reason why the member binding should only be registered by the container.

I planned, then, to use these to inject more services into containers as new features are added. E.g. implementing automatic List, Func, List injection for example. So yeah: big plans.

What about these 'options'?

  • Controlling whether targets can be registered more than once (i.e. disable the default behaviour)
  • Controlling how generic target containers FetchAll() - i.e. do they stop when one type gets a match, or combine
    all the generics which match
  • Potentially controlling whether overriding (target) containers create combined enumerables or not (now the default after a little bit of work on OverridingContainer should extend base enumerables #42 and OverridingTargetContainer should extend base enumerable #43)
  • Switching on and off contravariance (covariance possibly - but later)
    • Setting rules for whether more derived/more general matches are prioritised over exact matches.
  • I can think of many more - but there's no need to elaborate

Why can't options be done with behaviours?

Behaviours add functionality to a container that it doesn't know it has.

These options are about customising known behaviour - e.g. allowing or disallowing multiple registrations in TargetListContainer - and mean reading a known property, or field.

So, normally they'd be done with local vars and constructor parameters.

Problem is, we want them to be configuration-based AND to be configurable potentially on a per-type basis. Whereas the 'behaviours' that we have right now are actually just a fancy callback mechanism to inject registrations into the container, and the container has to know to invoke them.

These options will need to be in force from when a container is created, and so behaviours are not suitable.

But we might be able to use these options to deliver both the known configurables into new target containers; and the behaviours. We might then also be able to enforce the use of the behaviours through the container factory that I'm proposing...

@LordZoltan LordZoltan self-assigned this May 19, 2017
@LordZoltan
Copy link
Member Author

Total change - going instead with a simple Get/Set API which utilises the target container functionality behind the scenes. Will also allow you to set options on a per-type basis too.

check out 369bc79 for an early sketch

@LordZoltan
Copy link
Member Author

So I'm going with the SetOption<>/GetOption<> approach as I've now used it to implement #26 and to add another behaviour - which is to allow controlling of whether multiple targets are allowed to be registered for a type.

It's strongly-typed, allows for rich 'options' objects, and uses the ITargetContainer itself as storage, which means that - with a little bit of rewiring - all targets, child target containers and Containers are able to read those options.

You can also set options on a per-type basis - including on open generics (and have them automatically apply for closed generics) - and have them override a 'global' setting for that option. This means that you can, for example, configure a specific enumerable type not to match all possible variants of the generic, when the container-wide default is to do so. Equally, I intend to use it to control how covariance, and potentially contravariance, works in #44.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant