You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Dec 19, 2023. It is now read-only.
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
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...
The text was updated successfully, but these errors were encountered:
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.
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.
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
orGenericTargetContainer
- and container types (Container
,OverridingContainer
etc)What are behaviours and options for?
ITargetContainerBehaviour
s:ITargetContainer
forIEnumerable<>
IResolveContext
- registers a target that simply returns the input context (viaICompiledTarget
)Container behaviours:
IMemberBindingBehaviour
forConstructorTarget
Overriding container:
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.
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'?
all the generics which match
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...
The text was updated successfully, but these errors were encountered: