-
Notifications
You must be signed in to change notification settings - Fork 1
One Process to Rule Them All. Armature's Universal Dependency Resolution
Armature demonstrates a unique approach to handling the internal "plumbing" of dependency injection. Instead of introducing specialized mechanisms for tasks like constructor selection or argument resolution, it treats these internal operations as regular units within the build process. This means that the same rules and patterns used to build user-defined types are also applied to internal Armature logic.
This unified approach simplifies the framework and makes it more flexible. For instance, consider the task of selecting a constructor for a class. In Armature, this isn't handled by a special "constructor selector" but rather by a build action that treats the constructor itself as a unit to be built. This build action can then leverage the full power of build stack patterns and other build actions to determine which constructor is most appropriate based on the current context.
To distinguish these internal units from possible-the-same user-defined ones, Armature uses a special type of tag called a ServiceTag. Examples of service tags include:
-
ServiceTag.Constructor
: Used to identify units representing constructors. -
ServiceTag.PropertyCollection
: Used for units representing collections of properties. -
ServiceTag.Argument
: Used for units representing arguments for constructors or methods. These tags allow build stack patterns to specifically target and manipulate internal units as needed.
Let's say Armature needs to resolve an argument for a constructor parameter of type string
. This argument is represented as a unit with UnitId(ParameterInfo, ServiceTag.Argument) where the instance ParamterInfo is got by reflection from the corresponding constructor. Armature would then apply its build stack patterns to this unit, just like it would for any other type. For instance, a pattern might match the UnitId and use a CreateByFactoryMethodBuildAction to instantiate a string
object.
This unified approach offers several advantages:
Consistency: The same mechanisms are used for both user-defined and internal units, leading to a more consistent and predictable behavior.
Extensibility: The build process can be easily extended to handle new types of internal units without modifying the core framework.
Flexibility: Developers have full control over how internal units are built and can customize the behavior using the same tools and techniques used for user-defined types.