Dreamine.MVVM.Core 1.0.13
중요: 자동 등록된 타입은 기본적으로 Singleton으로 등록됩니다. 따라서 자동 발견된 ViewModel, Model, Event, Manager는 애플리케이션이 별도 수명으로 명시 등록하지 않는 한 반복 해석 시 동일 인스턴스를 유지합니다.
로딩중...
검색중...
일치하는것 없음
DreamineContainer.cs
이 파일의 문서화 페이지로 가기
1using System;
2using System.Collections.Generic;
3using System.Threading;
4using Dreamine.MVVM.Interfaces.DependencyInjection;
5
7{
16 public sealed class DreamineContainer : IServiceContainer, IDisposable
17 {
26 private readonly Dictionary<Type, ServiceDescriptor> _descriptors = new();
35 private readonly Dictionary<Type, object> _singletonInstances = new();
44 private readonly AsyncLocal<ResolutionContext?> _currentResolutionContext = new();
53 private readonly IObjectActivator _objectActivator;
62 private readonly object _syncRoot = new();
71 private bool _disposed;
72
83 {
84 }
85
110 public DreamineContainer(IObjectActivator objectActivator)
111 {
112 _objectActivator = objectActivator
113 ?? throw new ArgumentNullException(nameof(objectActivator));
114 }
115
133 where TImplementation : class
134 {
135 Register<TImplementation, TImplementation>();
136 }
137
163 where TService : class
164 where TImplementation : class, TService
165 {
166 Type serviceType = typeof(TService);
167 Type implementationType = typeof(TImplementation);
168
169 lock (_syncRoot)
170 {
171 _descriptors[serviceType] = new ServiceDescriptor(
172 serviceType,
173 implementationType,
174 factory: null,
175 instance: null,
176 lifetime: ServiceLifetime.Transient);
177 _singletonInstances.Remove(serviceType);
178 }
179 }
180
213 public void Register<TService>(Func<TService> factory)
214 where TService : class
215 {
216 if (factory is null)
217 {
218 throw new ArgumentNullException(nameof(factory));
219 }
220
221 Type serviceType = typeof(TService);
222
223 lock (_syncRoot)
224 {
225 _descriptors[serviceType] = new ServiceDescriptor(
226 serviceType,
227 implementationType: null,
228 factory: () => factory(),
229 instance: null,
230 lifetime: ServiceLifetime.Transient);
231 _singletonInstances.Remove(serviceType);
232 }
233 }
234
267 public void RegisterSingleton<TService>(TService instance)
268 where TService : class
269 {
270 if (instance is null)
271 {
272 throw new ArgumentNullException(nameof(instance));
273 }
274
275 Type serviceType = typeof(TService);
276
277 lock (_syncRoot)
278 {
279 _descriptors[serviceType] = new ServiceDescriptor(
280 serviceType,
281 instance.GetType(),
282 factory: null,
283 instance,
284 lifetime: ServiceLifetime.Singleton);
285
286 _singletonInstances[serviceType] = instance;
287 }
288 }
289
307 where TImplementation : class
308 {
309 RegisterSingleton<TImplementation, TImplementation>();
310 }
311
337 where TService : class
338 where TImplementation : class, TService
339 {
340 Type serviceType = typeof(TService);
341 Type implementationType = typeof(TImplementation);
342
343 lock (_syncRoot)
344 {
345 _descriptors[serviceType] = new ServiceDescriptor(
346 serviceType,
347 implementationType,
348 factory: null,
349 instance: null,
350 lifetime: ServiceLifetime.Singleton);
351 _singletonInstances.Remove(serviceType);
352 }
353 }
354
387 public bool IsRegistered(Type serviceType)
388 {
389 if (serviceType is null)
390 {
391 throw new ArgumentNullException(nameof(serviceType));
392 }
393
394 lock (_syncRoot)
395 {
396 return _descriptors.ContainsKey(serviceType);
397 }
398 }
399
424 public TService Resolve<TService>()
425 where TService : class
426 {
427 return (TService)Resolve(typeof(TService));
428 }
429
462 public bool TryResolve<TService>(out TService? result)
463 where TService : class
464 {
465 try
466 {
467 result = Resolve<TService>();
468 return true;
469 }
470 catch (InvalidOperationException)
471 {
472 result = null;
473 return false;
474 }
475 }
476
509 public object Resolve(Type serviceType)
510 {
511 if (serviceType is null)
512 {
513 throw new ArgumentNullException(nameof(serviceType));
514 }
515
516 // AsyncLocal context setup is per-async-flow and must live outside the lock
517 // so that nested Resolve calls on the same flow see the same context
518 // without requiring lock re-entry ordering to be preserved.
519 ResolutionContext? previousContext = _currentResolutionContext.Value;
520 bool ownsContext = previousContext is null;
521 if (ownsContext)
522 {
523 _currentResolutionContext.Value = new ResolutionContext();
524 }
525
526 try
527 {
528 lock (_syncRoot)
529 {
530 return ResolveCore(serviceType);
531 }
532 }
533 finally
534 {
535 if (ownsContext)
536 {
537 _currentResolutionContext.Value = null;
538 }
539 }
540 }
541
574 private object ResolveCore(Type serviceType)
575 {
576 if (_singletonInstances.TryGetValue(serviceType, out object? singleton))
577 {
578 return singleton;
579 }
580
581 if (!_descriptors.TryGetValue(serviceType, out ServiceDescriptor? descriptor))
582 {
583 if (CanCreateUnregisteredConcreteType(serviceType))
584 {
585 return CreateConcrete(serviceType);
586 }
587
588 throw new InvalidOperationException(
589 $"Service [{serviceType.FullName}] is not registered.");
590 }
591
592 if (descriptor.Factory is not null)
593 {
594 return descriptor.Factory();
595 }
596
597 if (descriptor.Instance is not null)
598 {
599 return descriptor.Instance;
600 }
601
602 if (descriptor.ImplementationType is null)
603 {
604 throw new InvalidOperationException(
605 $"Service [{serviceType.FullName}] has no implementation type.");
606 }
607
608 object instance = CreateConcrete(descriptor.ImplementationType);
609
610 if (descriptor.Lifetime == ServiceLifetime.Singleton)
611 {
612 _singletonInstances[serviceType] = instance;
613 }
614
615 return instance;
616 }
617
650 private object CreateConcrete(Type implementationType)
651 {
652 ResolutionContext context = _currentResolutionContext.Value ?? new ResolutionContext();
653 if (!context.TryEnter(implementationType))
654 {
655 throw new InvalidOperationException(
656 $"Circular dependency detected while resolving [{implementationType.FullName}].");
657 }
658
659 try
660 {
661 return _objectActivator.CreateInstance(implementationType, this);
662 }
663 finally
664 {
665 context.Exit(implementationType);
666 }
667 }
668
677 public void Dispose()
678 {
679 List<object> toDispose;
680
681 lock (_syncRoot)
682 {
683 if (_disposed)
684 {
685 return;
686 }
687
688 _disposed = true;
689 toDispose = new List<object>(_singletonInstances.Values);
690 _singletonInstances.Clear();
691 _descriptors.Clear();
692 }
693
694 foreach (object instance in toDispose)
695 {
696 if (instance is IDisposable disposable)
697 {
698 disposable.Dispose();
699 }
700 }
701 }
702
727 private static bool CanCreateUnregisteredConcreteType(Type type)
728 {
729 return type.IsClass &&
730 !type.IsAbstract &&
731 !type.IsGenericTypeDefinition;
732 }
733 }
734}
readonly AsyncLocal< ResolutionContext?> _currentResolutionContext
readonly Dictionary< Type, ServiceDescriptor > _descriptors
readonly Dictionary< Type, object > _singletonInstances