/src/LinFu.IoC/Scope.cs

http://github.com/philiplaureano/LinFu · C# · 97 lines · 55 code · 18 blank · 24 comment · 13 complexity · 6dc6a01397ca2c146e68d3b203dd2267 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. using LinFu.IoC.Configuration;
  5. using LinFu.IoC.Interfaces;
  6. namespace LinFu.IoC
  7. {
  8. /// <summary>
  9. /// Represents a class that keeps track of all the disposable objects
  10. /// created within a service container and disposes them when
  11. /// the scope itself has been disposed.
  12. /// </summary>
  13. public class Scope : IScope, IPostProcessor, IInitialize
  14. {
  15. private readonly List<WeakReference> _disposables = new List<WeakReference>();
  16. private IServiceContainer _container;
  17. private bool _disposed;
  18. private int _threadId;
  19. /// <summary>
  20. /// Inserts the scope into the target <paramref name="source">container</paramref>.
  21. /// </summary>
  22. /// <param name="source">The container that will hold the scope instance.</param>
  23. public void Initialize(IServiceContainer source)
  24. {
  25. lock (this)
  26. {
  27. _container = source;
  28. // Use the same thread ID as the service instantiation call
  29. _threadId = Thread.CurrentThread.ManagedThreadId;
  30. // Monitor the container for
  31. // any IDisposable instances that need to be disposed
  32. _container.PostProcessors.Add(this);
  33. }
  34. }
  35. /// <summary>
  36. /// Monitors the <see cref="IServiceContainer" /> for any services that are created and automatically disposes them
  37. /// once the <see cref="IScope" /> is disposed.
  38. /// </summary>
  39. /// <param name="result">The <see cref="IServiceRequestResult" /> that describes the service being instantiated.</param>
  40. public void PostProcess(IServiceRequestResult result)
  41. {
  42. if (_disposed)
  43. return;
  44. // Only handle requests from the same thread
  45. if (_threadId != Thread.CurrentThread.ManagedThreadId)
  46. return;
  47. // Ignore any nondisposable instances
  48. if (result.ActualResult == null || !(result.ActualResult is IDisposable))
  49. return;
  50. var disposable = result.ActualResult as IDisposable;
  51. var weakRef = new WeakReference(disposable);
  52. _disposables.Add(weakRef);
  53. }
  54. /// <summary>
  55. /// Disposes the services that have been created while the scope has been active.
  56. /// </summary>
  57. public void Dispose()
  58. {
  59. if (_disposed)
  60. return;
  61. if (_threadId != Thread.CurrentThread.ManagedThreadId)
  62. throw new InvalidOperationException(
  63. "The scope object can only be disposed from within the thread that created it.");
  64. // Dispose all child objects
  65. foreach (var item in _disposables)
  66. {
  67. if (item == null)
  68. continue;
  69. var target = item.Target as IDisposable;
  70. if (target == null)
  71. continue;
  72. target.Dispose();
  73. }
  74. _disposed = true;
  75. // Remove the scope from the target container
  76. _container.PostProcessors.Remove(this);
  77. }
  78. }
  79. }