Constructs a new ServiceProvider that makes use of the given services.
Creates a new scope.
Destroys a scope.
During construction, the ServiceProvider will perform a check to ensure that none of its registered services contain a dependency loop, i.e. making sure that no service directly/indirectly depends on itself.
If you're creating your ServiceInfo via the ServiceInfo.asSingleton, ServiceInfo.asTransient, or ServiceInfo.asScoped constructors, then this functionality is entirely automatic.
If however you're using the asXXXRuntime constructor varient, then it is down to the user to provide an array of TypeInfo to that constructor, representing the service's dependencies. Failing to provide the correct data will cause this guard check to not detect the loop, and later down the line this will cause an infinite loop leading into a crash.
In the future, I may add a version() block that will make ServiceProvider.getServiceOrNull also perform dependency loop checks. The reason this is not performed by default is due to performance concerns (especially once your services start to grow in number).
During construction, the ServiceProvider will perform a check to ensure that none of its registered services contains a dependency on another service with an incompatible lifetime.
Likewise with depenency checking (see section above), you will need to ensure that you provide the correct data when using the asXXXRuntime constructors for ServiceInfo.
The following is a table of valid lifetime pairings:
* Transient - [Transient, Singleton]
* Scoped - [Transient, Scoped, Singleton]
* Singleton - [Transient, Singleton]
Provides most of the functionality for managing and using services.