Object lifetime management of IOC containers
If you have been using the IOC container, you may have used some object lifetime management models (Lifetime Management). By managing object lifetimes, the reuse of objects is made possible. It also enables the container to control how object instances are created and managed.
The object lifetime management model provided by unity is accomplished by deriving classes Lifetimemanager from the abstract class. Unity will create the lifetime manager for each type of registration. Whenever UnityContainer needs to create a new object instance, the lifetime manager for that object type is detected first, and whether an object instance is already available. If no object instance is available, UnityContainer constructs the object instance based on the configured information and gives the object to the object lifetime Manager.
Lifetimemanager
Lifetimemanager is an abstract class that implements the Ilifetimepolicy interface. The class is used as the parent of all built-in or custom lifetime managers. It defines 3 methods: GetValue-Returns an instance of an object that has been stored in the lifetime manager. SetValue-Stores a new object instance into the lifetime manager. RemoveValue-Deletes the stored object instance from the lifetime manager. The default implementation of the UnityContainer will not call this method, but it can be invoked in a custom container extension.
Unity has built-in 6 life-cycle management models, 2 of which are responsible for the creation of object instances and the destruction of object instances (disposing).
Transientlifetimemanager-Generates a new type object instance for each request. (Default behavior)
ContainerControlledLifetimeManager-Implements the Singleton object instance. When the container is disposed, the object instance is also disposed.
Hierarchicalifetimemanager-Implements the Singleton object instance. However, the child container does not share the parent container instance, but instead creates a singleton object instance for the word container. When the container is disposed, the object instance is also disposed.
Externallycontrolledlifetimemanager-Implements a singleton object instance, but the container holds only the weak reference (WeakReference) of that object, so the lifetime of the object is controlled by an external reference.
Perthreadlifetimemanager-Generates singleton object instances for each thread, implemented by ThreadStatic.
Perresolvelifetimemanager-Implements a behavior similar to Transientlifetimemanager, generating a new type object instance for each request. The difference is that object instances can be reused during the buildup process.
Code Double
Copy Code code as follows:
public interface Iexample:idisposable
{
void SayHello ();
}
public class Example:iexample
{
private bool _disposed = false;
Private readonly Guid _key = Guid.NewGuid ();
public void SayHello ()
{
if (_disposed)
{
throw new ObjectDisposedException ("Example",
String. Format ("{0} is already disposed!", _key));
}
Console.WriteLine ("{0} says hello in thread {1}!", _key,
THREAD.CURRENTTHREAD.MANAGEDTHREADID);
}
public void Dispose ()
{
if (!_disposed)
{
_disposed = true;
}
}
}
Transientlifetimemanager
Transientlifetimemanager is the Unity default lifetime manager. The internal implementation is empty, which means that each container creates and returns a new object instance, and of course the container is not responsible for storing and destroying the object instance.
Copy Code code as follows:
private static void Testtransientlifetimemanager ()
{
iexample example;
using (Iunitycontainer container = new UnityContainer ())
{
Container. Registertype (typeof (Iexample), typeof (Example),
New Transientlifetimemanager ());
Each one gets its own instance
Container. Resolve<iexample> (). SayHello ();
Example = Container. Resolve<iexample> ();
}
Container is disposed but Example instance still lives
All previously created instances weren ' t disposed!
Example. SayHello ();
Console.readkey ();
}
ContainerControlledLifetimeManager
ContainerControlledLifetimeManager will provide a singleton instance of the registered type object for UnityContainer and its child containers. It creates a new object instance only the first time a registered type is requested, and the object instance is stored in the Lifetime manager and has been reused. When the container is destructor, the lifetime manager invokes RemoveValue to destroy the stored object.
The Singleton object instance corresponds to each object type registration, and if the same object type is registered multiple times, a single instance is created for each registration.
Copy Code code as follows:
private static void Testcontainercontrolledlifetimemanager ()
{
iexample example;
using (Iunitycontainer container = new UnityContainer ())
{
Container. Registertype (typeof (Iexample), typeof (Example),
New ContainerControlledLifetimeManager ());
Iunitycontainer firstsub = null;
Iunitycontainer secondsub = null;
Try
{
Firstsub = container. Createchildcontainer ();
Secondsub = container. Createchildcontainer ();
All containers share same instance
Each resolve returns same instance
Firstsub.resolve<iexample> (). SayHello ();
Run one resolving in the other thread and still receive same instance
Thread thread = new Thread (
() => secondsub.resolve<iexample> (). SayHello ());
Thread. Start ();
container. Resolve<iexample> (). SayHello ();
example = container. Resolve<iexample> ();
Thread. Join ();
}
finally
{
if (firstsub!= null) firstsub.dispose ();
if (secondsub!= null) secondsub.dispose ();
}
}
Try
{
Exception-instance has been disposed with container
Example. SayHello ();
}
catch (ObjectDisposedException ex)
{
Console.WriteLine (ex. message);
}
Console.readkey ();
}
The Hierarchicallifetimemanager class derives from the ContainerControlledLifetimeManager and inherits all the behavior of the parent class. The difference from the parent class is in the lifetime manager behavior in the child container. ContainerControlledLifetimeManager shares the same object instance, which is included in the child container. Hierarchicallifetimemanager is shared only within the same container, and each child container has its own instance of the object.
Copy Code code as follows:
private static void Testhierarchicallifetimemanager ()
{
iexample example;
using (Iunitycontainer container = new UnityContainer ())
{
Container. Registertype (typeof (Iexample), typeof (Example),
New Hierarchicallifetimemanager ());
Iunitycontainer firstsub = null;
Iunitycontainer secondsub = null;
try
{
firstsub = container. Createchildcontainer ();
secondsub = container. Createchildcontainer ();
//Each subcontainer has its own instance
firstsub.resolve<iexample> (). SayHello ();
secondsub.resolve<iexample> (). SayHello ();
container. Resolve<iexample> (). SayHello ();
example = firstsub.resolve<iexample> ();
}
finally
{
if (firstsub!= null) firstsub.dispose ();
if (secondsub!= null) secondsub.dispose ();
}
}
Try
{
Exception-instance has been disposed with container
Example. SayHello ();
}
catch (ObjectDisposedException ex)
{
Console.WriteLine (ex. message);
}
Console.readkey ();
}
Externallycontrolledlifetimemanager
The lifetime of an object instance in Externallycontrolledlifetimemanager will have unitycontainer external implementation control. This lifetime manager internally stores a weakreference of the provided object instance. Therefore, if there is no strong reference to the object instance in the external implementation of the UnityContainer container, the object instance is reclaimed by GC. When the object type instance is requested again, a new object instance is created.
Copy Code code as follows:
private static void Testexternallycontrolledlifetimemanager ()
{
iexample example;
using (Iunitycontainer container = new UnityContainer ())
{
Container. Registertype (typeof (Iexample), typeof (Example),
New Externallycontrolledlifetimemanager ());
Same instance is used in following
Container. Resolve<iexample> (). SayHello ();
Container. Resolve<iexample> (). SayHello ();
Run Garbate collector. Stored Example instance would be released
Beacuse there is no reference for it and Lifetimemanager holds
Only WeakReference
Gc. Collect ();
Object stored targeted by WeakReference is released
New instance is created!
Container. Resolve<iexample> (). SayHello ();
Example = Container. Resolve<iexample> ();
}
Example. SayHello ();
Console.readkey ();
}
This result proves that strong reference still exists, do not know why? If you find the reason, please tell me, thank you.
Perthreadlifetimemanager
The Perthreadlifetimemanager model provides a single instance per thread feature. All object instances are internally stored in the ThreadStatic collection. The container does not track the creation of object instances and is not responsible for dipose.
Copy Code code as follows:
private static void Testperthreadlifetimemanager ()
{
iexample example;
using (Iunitycontainer container = new UnityContainer ())
{
Container. Registertype (typeof (Iexample), typeof (Example),
New Perthreadlifetimemanager ());
action<int> action = delegate (int sleep)
{
Both calls use same instance per thread
Container. Resolve<iexample> (). SayHello ();
Thread.Sleep (sleep);
Container. Resolve<iexample> (). SayHello ();
};
Thread thread1 = new Thread (a) => action. Invoke ((int) a));
Thread thread2 = new Thread (a) => action. Invoke ((int) a));
Thread1. Start (50);
Thread2. Start (50);
Thread1. Join ();
Thread2. Join ();
Example = Container. Resolve<iexample> ();
}
Example. SayHello ();
Console.readkey ();
}
Perresolvelifetimemanager
Perresolvelifetimemanager is a special model built in unity. Because Unity uses a separate logic to handle the per-resolve lifetimes of registered types. Each time a request resolve a type object, UnityContainer creates and returns a new object instance.
Copy Code code as follows:
private static void Testperresolvelifetimemanager ()
{
iexample example;
using (iunitycontainer container = new UnityContainer ())
{
container. Registertype (typeof (Iexample), typeof (Example),
New Perresolvelifetimemanager ());
container. Resolve<iexample> (). SayHello ();
container. Resolve<iexample> (). SayHello ();
example = container. Resolve<iexample> ();
}
example. SayHello ();
Console.readkey ();
}