DotNetDupe 4.0.6
C++17/20 Implementation of the .NET Base Class Library (BCL)
Loading...
Searching...
No Matches
ServiceProvider.cpp
Go to the documentation of this file.
1#include "pch.h"
4#include <unordered_map>
5#include <vector>
6#include <typeindex>
7
8namespace DotNetDupe {
9 namespace Extensions {
10 namespace DependencyInjection {
11
12 // Lightweight proxy class to safely wrap a ServiceProvider pointer
13 // without ownership issues or double deletion.
14 class ServiceProviderProxy : public DotNetDupe::System::IServiceProvider {
15 public:
16 ServiceProviderProxy(ServiceProvider* pProvider) : m_pProvider(pProvider) {}
17 ~ServiceProviderProxy() override = default;
18
19 DotNetDupe::System::SmartPointer<DotNetDupe::System::Object> GetService(const std::type_index& serviceType) override {
21 return m_pProvider->GetService(serviceType);
22 }
23
24 private:
25 ServiceProvider* m_pProvider;
26 };
27
28 // --- ServiceProvider Implementation ---
29
32 if (descriptor.GetInstance()) {
33 return descriptor.GetInstance();
34 }
35
37 if (descriptor.GetFactory()) {
40 );
41 return descriptor.GetFactory()(pProxy);
42 }
43
45 return nullptr;
46 }
47
48 struct ServiceProvider::Impl {
49 std::unordered_map<std::type_index, ServiceDescriptor> mapDescriptors;
50 std::unordered_map<std::type_index, DotNetDupe::System::SmartPointer<DotNetDupe::System::Object>> pMapSingletons;
51 std::unordered_map<std::type_index, DotNetDupe::System::SmartPointer<DotNetDupe::System::Object>> pMapScoped;
52 std::vector<DotNetDupe::System::SmartPointer<DotNetDupe::System::IO::IDisposable>> pvDisposables;
54
57 if (pInst.IsNull()) return;
58
61 if (!pDisp.IsNull()) {
62 pvDisposables.push_back(pDisp);
63 }
64 }
65
66 DotNetDupe::System::SmartPointer<DotNetDupe::System::Object> ResolveSingleton(ServiceProvider* pSelf, const ServiceDescriptor& desc) {
69
71 auto it = pMapSingletons.find(desc.GetServiceType());
72 if (it != pMapSingletons.end()) return it->second;
73
75 auto pInst = InstantiateService(pSelf, desc);
76 if (!pInst.IsNull()) {
77 pMapSingletons[desc.GetServiceType()] = pInst;
78 Track(pInst);
79 }
80 return pInst;
81 }
82
83 DotNetDupe::System::SmartPointer<DotNetDupe::System::Object> ResolveScoped(ServiceProvider* pSelf, const ServiceDescriptor& desc) {
86
88 auto it = pMapScoped.find(desc.GetServiceType());
89 if (it != pMapScoped.end()) return it->second;
90
92 auto pInst = InstantiateService(pSelf, desc);
93 if (!pInst.IsNull()) {
94 pMapScoped[desc.GetServiceType()] = pInst;
95 Track(pInst);
96 }
97 return pInst;
98 }
99
100 DotNetDupe::System::SmartPointer<DotNetDupe::System::Object> ResolveTransient(ServiceProvider* pSelf, const ServiceDescriptor& desc) {
102 auto pInst = InstantiateService(pSelf, desc);
103
105 if (!pInst.IsNull()) {
107 Track(pInst);
108 }
109 return pInst;
110 }
111 };
112
114 : m_bIsRoot(true), m_pRootProvider(nullptr), m_pImpl(DotNetDupe::System::SmartPointer<Impl>::NewShared()) {
116 for (int iIdx = 0; iIdx < collection.GetCount(); ++iIdx) {
117 const ServiceDescriptor& descriptor = collection[iIdx];
118 m_pImpl->mapDescriptors.insert({ descriptor.GetServiceType(), descriptor });
119 }
120 }
121
123 : m_bIsRoot(false), m_pRootProvider(pRootProvider), m_pImpl(DotNetDupe::System::SmartPointer<Impl>::NewShared()) {
125 }
126
131
135
137 if (serviceType == typeid(DotNetDupe::System::IServiceProvider)) {
140 );
141 }
142 if (serviceType == typeid(IServiceScopeFactory)) {
145 );
146 }
147
149 ServiceProvider* pRoot = m_bIsRoot ? this : m_pRootProvider;
150 auto it = pRoot->m_pImpl->mapDescriptors.find(serviceType);
151 if (it == pRoot->m_pImpl->mapDescriptors.end()) {
152 return nullptr;
153 }
154
156 return ResolveService(it->second);
157 }
158
159 DotNetDupe::System::SmartPointer<DotNetDupe::System::Object> ServiceProvider::ResolveService(const ServiceDescriptor& descriptor) {
161 if (descriptor.GetLifetime() == ServiceLifetime::Singleton) {
162 ServiceProvider* pRoot = m_bIsRoot ? this : m_pRootProvider;
163 return pRoot->m_pImpl->ResolveSingleton(this, descriptor);
164 }
165
167 if (descriptor.GetLifetime() == ServiceLifetime::Scoped) {
168 if (m_bIsRoot) {
169 throw DotNetDupe::System::InvalidOperationException("Cannot resolve scoped service from root provider.");
170 }
171 return m_pImpl->ResolveScoped(this, descriptor);
172 }
173
175 return m_pImpl->ResolveTransient(this, descriptor);
176 }
177
180 if (m_pImpl.IsNull()) return;
182
184 for (auto it = m_pImpl->pvDisposables.rbegin(); it != m_pImpl->pvDisposables.rend(); ++it) {
185 if (!it->IsNull()) {
186 (*it)->Dispose();
187 }
188 }
189 m_pImpl->pvDisposables.clear();
190
192 m_pImpl->pMapSingletons.clear();
193 m_pImpl->pMapScoped.clear();
194 }
195
196 // --- ServiceScope Implementation ---
197
199 : m_pProvider(std::move(pProvider)) {
201 }
202
207
212
215 if (!m_pProvider.IsNull()) {
216 m_pProvider->Dispose();
217 m_pProvider = nullptr;
218 }
219 }
220
221 // --- ServiceScopeFactory Implementation ---
222
224 : m_pProvider(pProvider) {
226 }
227
236 }
237 }
238}
Provides an RAII-style scoped lock wrapper around synchronization primitives.
Specifies the contract for a collection of service descriptors.
Defines a factory interface used to create instances of IServiceScope.
Describes a service with its service type, implementation, and lifetime.
std::type_index GetServiceType() const
Gets the service type represented by this descriptor.
const FactoryType & GetFactory() const
Gets the optional factory function delegate.
const DotNetDupe::System::SmartPointer< DotNetDupe::System::Object > & GetInstance() const
Gets the optional pre-existing singleton instance.
ServiceLifetime GetLifetime() const
Gets the lifetime scope configured for this service.
Default IoC service provider for resolving dependencies.
void Dispose() override
Disposes all resolved singleton instances and clears cached references.
ServiceProvider(const IServiceCollection &collection)
Initializes a root ServiceProvider from an IServiceCollection.
~ServiceProvider() override
Destructor releasing resolved services.
ServiceScopeFactory(ServiceProvider *pProvider)
Initializes a ServiceScopeFactory bound to a root provider.
DotNetDupe::System::SmartPointer< IServiceScope > CreateScope() override
Creates a new child IServiceScope.
DotNetDupe::System::SmartPointer< DotNetDupe::System::IServiceProvider > GetServiceProvider() const override
Gets the scoped IServiceProvider.
void Dispose() override
Disposes the scope and all scoped instances created within it.
~ServiceScope() override
Destructor disposing the child scope provider.
ServiceScope(DotNetDupe::System::SmartPointer< ServiceProvider > pProvider)
Initializes a ServiceScope wrapping a scoped ServiceProvider.
int GetCount() const
Gets the number of elements contained in the List.
Definition List.h:100
Provides a mechanism for releasing unmanaged resources.
Definition IDisposable.h:13
Defines a mechanism for retrieving a service object; that is, an object that provides custom support ...
SmartPointer< T > GetService()
Gets the service object of the specified generic type T.
The exception that is thrown when a method call is invalid for the object's current state.
A unified smart pointer that supports both unique and shared ownership semantics.
static SmartPointer< T > NewShared()
Creates a Shared SmartPointer, default constructing T.
bool IsNull() const noexcept
Checks if the SmartPointer is null.
SmartPointer< U > DynamicCast() const
Dynamically casts the managed pointer to another type U and returns a new SmartPointer sharing owners...
Provides a re-entrant mutual exclusion primitive for thread synchronization.
@ Scoped
Specifies that a new instance of the service will be created for each scope.
@ Singleton
Specifies that a single instance of the service will be created.
static DotNetDupe::System::SmartPointer< DotNetDupe::System::Object > InstantiateService(ServiceProvider *pSelf, const ServiceDescriptor &descriptor)
Lock< CriticalSection > CriticalSectionLock
Convenience alias for Lock<CriticalSection>.
Definition Lock.h:71