11using System ;
2+ using System . Threading ;
3+ using Unity . Exceptions ;
24using Unity . Lifetime ;
35
46namespace Unity . Microsoft . DependencyInjection . Lifetime
57{
6- public class InjectionSingletonLifetimeManager : ContainerControlledLifetimeManager
8+ public class InjectionSingletonLifetimeManager : LifetimeManager , IRequiresRecovery
9+
710 {
811 #region Fields
912
10- private ILifetimeContainer _lifetime ;
11-
13+ private readonly object _lockObj = new object ( ) ;
14+ private readonly ILifetimeContainer _container ;
15+ private object _value ;
16+
1217 #endregion
1318
1419
15- public InjectionSingletonLifetimeManager ( ILifetimeContainer lifetime )
20+ #region Constructors
21+
22+ public InjectionSingletonLifetimeManager ( ILifetimeContainer container )
1623 {
17- _lifetime = lifetime ;
24+ _container = container ?? throw new ArgumentNullException ( nameof ( container ) ) ;
1825 }
1926
27+ #endregion
28+
2029
21- protected override void SynchronizedSetValue ( object newValue , ILifetimeContainer container = null )
30+ #region LifetimeManager
31+
32+ /// <summary>
33+ /// Remove the given object from backing store.
34+ /// </summary>
35+ /// <param name="container">Instance of container</param>
36+ public override void RemoveValue ( ILifetimeContainer container = null )
2237 {
23- base . SynchronizedSetValue ( newValue , container ) ;
24- _lifetime . Add ( new DisposableAction ( ( ) => RemoveValue ( _lifetime ) ) ) ;
38+ if ( _value == null ) return ;
39+ if ( _value is IDisposable disposable )
40+ {
41+ disposable . Dispose ( ) ;
42+ }
43+ _value = null ;
2544 }
2645
2746 protected override LifetimeManager OnCreateLifetimeManager ( )
2847 {
29- return new InjectionSingletonLifetimeManager ( _lifetime ) ;
48+ return new InjectionSingletonLifetimeManager ( _container ) ;
49+ }
50+
51+
52+ /// <summary>
53+ /// Retrieve a value from the backing store associated with this Lifetime policy.
54+ /// </summary>
55+ /// <returns>the object desired, or null if no such object is currently stored.</returns>
56+ /// <remarks>Calls to this method acquire a lock which is released only if a non-null value
57+ /// has been set for the lifetime manager.</remarks>
58+ public override object GetValue ( ILifetimeContainer container = null )
59+ {
60+ Monitor . Enter ( _lockObj ) ;
61+ if ( _value != null )
62+ {
63+ Monitor . Exit ( _lockObj ) ;
64+ }
65+ return _value ;
3066 }
3167
3268
69+ /// <summary>
70+ /// Stores the given value into backing store for retrieval later.
71+ /// </summary>
72+ /// <param name="newValue">The object being stored.</param>
73+ /// <param name="container">The container this value belongs to.</param>
74+ /// <remarks>Setting a value will attempt to release the lock acquired by
75+ /// <see cref="SynchronizedLifetimeManager.GetValue"/>.</remarks>
76+ public override void SetValue ( object newValue , ILifetimeContainer container = null )
77+ {
78+ _value = newValue ;
79+ if ( _value is IDisposable ) _container . Add ( new DisposableAction ( ( ) => RemoveValue ( _container ) ) ) ;
80+ TryExit ( ) ;
81+ }
82+
83+ #endregion
84+
85+
86+ #region IRequiresRecovery
87+
88+ /// <summary>
89+ /// A method that does whatever is needed to clean up
90+ /// as part of cleaning up after an exception.
91+ /// </summary>
92+ /// <remarks>
93+ /// Don't do anything that could throw in this method,
94+ /// it will cause later recover operations to get skipped
95+ /// and play real havoc with the stack trace.
96+ /// </remarks>
97+ public void Recover ( )
98+ {
99+ TryExit ( ) ;
100+ }
101+
102+ protected virtual void TryExit ( )
103+ {
104+ #if ! NET40
105+ // Prevent first chance exception when abandoning a lock that has not been entered
106+ if ( ! Monitor . IsEntered ( _lockObj ) ) return ;
107+ #endif
108+ try
109+ {
110+ Monitor . Exit ( _lockObj ) ;
111+ }
112+ catch ( SynchronizationLockException )
113+ {
114+ // Noop here - we don't hold the lock and that's ok.
115+ }
116+ }
117+
118+ #endregion
119+
120+
33121 #region Nested Types
34122
35123 private class DisposableAction : IDisposable
@@ -48,6 +136,5 @@ public void Dispose()
48136 }
49137
50138 #endregion
51-
52139 }
53140}
0 commit comments