Jaa


Deferring the Resolution of Objects

patterns & practices Developer Center

Download codeDownload PDFOrder Paperback

Unity provides two techniques to facilitate holding a reference to an object you need, but do not want to construct right away. Instead of creating a factory for the type and injecting the factory into your class, then using it to create the type you want, you can use the .NET standard type Lazy<T> (C#) or or Lazy(Of T) (Visual Basic) or the .NET standard type Func<T> (C#) or Func(Of T) (Visual Basic) with the Resolve method.

Using Lazy<T> with the Resolve Method

If you use the type Lazy<T> (C#) or Lazy(Of T) (Visual Basic) with the Resolve method, it returns an instance of Lazy<T>. The type argument of the Lazy<T> object that you resolve specifies the type of the object that you want to resolve from the container and initialize lazily.

Note

Use lazy initialization to defer the creation of a large or resource-intensive object, or the execution of a resource-intensive task, particularly when such creation or execution might not occur during the lifetime of the program.

The following code sample shows how you resolve an instance of MyClass that will be lazily initialized.

// Create a Unity container
IUnityContainer myContainer = new UnityContainer();

// Register a mapping for the IMyClass interface to the MyClass type
myContainer.RegisterType<IMyClass, MyClass>();
 
// ... other code here...

// Create a Lazy instance for the IMyClass interface type
var lazy = myContainer.Resolve<Lazy<IMyClass>>();

// ... other code here...

IMyClass myClassInstance = lazy.Value;
' Create a Unity container
Dim myContainer As IUnityContainer = New UnityContainer()

' Register a mapping for the IMyClass interface to the MyClass type
myContainer.RegisterType(Of IMyClass, [MyClass])()

' ... other code here...

' Create a Lazy instance for the IMyClass interface type
Dim lazy = myContainer.Resolve(Of Lazy(Of IMyClass))()

' ... other code here...

Dim myClassInstance As IMyClass = lazy.Value

You can also use named (non-default) registrations by including the registration name in the call to the Resolve method and the RegisterType method, just as you would when using these methods for non-deferred resolution.

In addition, you can use this feature to perform deferred resolution of multiple named registrations, as an alternative to using the ResolveAll method. For example, if you have multiple named registrations for the IMyClass interface to suitable concrete types, you can obtain a collection of the resolved types. The following code illustrates this.

IUnityContainer myContainer = new UnityContainer();
myContainer.RegisterType<IMyClass, FirstClass>("First");
myContainer.RegisterType<IMyClass, SecondClass>("Second");
myContainer.RegisterType<IMyClass, ThirdClass>("Third");

// ... other code here ...

var lazy = myContainer.Resolve<Lazy<IEnumerable<IMyClass>>>();

// ... other code here ...

IEnumerable<IMyClass> myClassInstances = lazy.Value;
Dim myContainer As IUnityContainer = New UnityContainer()
myContainer.RegisterType(Of IMyClass, FirstClass)("First")
myContainer.RegisterType(Of IMyClass, SecondClass)("Second")
myContainer.RegisterType(Of IMyClass, ThirdClass)("Third")

' ... other code here ...

Dim lazy = myContainer.Resolve(Of Lazy(Of IEnumerable(Of IMyClass)))()

' ... other code here ...

Dim myClassInstances As IEnumerable(Of IMyClass) = lazy.Value

For more information about lazy initialization, see the topic Lazy<T> Class on MSDN.

Using Func<T> with the Resolve Method

If you use the type Func<T> (C#) or Func(Of T) (Visual Basic) with the Resolve method, it returns a delegate that, when invoked, calls into the container and returns an instance of the specified type (in this case, T).

You can even create a delegate in this way without creating a registration or mapping for the specified type in the container if you wish. Because the resolve action only takes place when you invoke the delegate, subsequent registrations added to the container are available when the target object is resolved. This means that you can manipulate the registrations and mappings in the container at any point before you resolve the target object (although you can obviously register the type before you create the delegate if you prefer).

For example, you can create a delegate for a component named MyClass, and then register a mapping for it and perform deferred resolution when required using the following code.

// Create a Unity container
IUnityContainer myContainer = new UnityContainer();

// Create a delegate for the IMyClass interface type
var resolver = myContainer.Resolve<Func<IMyClass>>();

// ... other code here...

// Register a mapping for the IMyClass interface to the MyClass type
myContainer.RegisterType<IMyClass, MyClass>();

// Resolve the mapped target object
IMyClass myClassInstance = resolver();
' Create a Unity container
Dim myContainer As IUnityContainer = New UnityContainer()

' Create a delegate for the IMyClass interface type
Dim resolver = myContainer.Resolve(Of Func(Of IMyClass))()

' ... other code here...

' Register a mapping for the IMyClass interface to the MyClass type
myContainer.RegisterType(Of IMyClass, MyClass)()

' Resolve the mapped target object
Dim myClassInstance As IMyClass = resolver()

You can use this approach when you resolve the type using the Resolve method, or you can specify the delegate when you configure constructor, property setter, or method call injection. You can also use named (non-default) registrations by including the registration name in the call to the Resolve method and the RegisterType method, just as you would when using these methods for non-deferred resolution.

In addition, you can use this feature to perform deferred resolution of multiple named registrations, as an alternative to using the ResolveAll method. For example, if you have multiple named registrations for the IMyClass interface to suitable concrete types, you can obtain a collection of the resolved types. The following code illustrates this.

// Create a Unity container
IUnityContainer myContainer = new UnityContainer();

// Create an IEnumerable resolver for the IMyClass interface type
var resolver = myContainer.Resolve<Func<IEnumerable<IMyClass>>>();

// ... other code here...

// Register mappings for the IMyClass interface to appropriate concrete types
myContainer.RegisterType<IMyClass, FirstClass>("First");
myContainer.RegisterType<IMyClass, SecondClass>("Second");
myContainer.RegisterType<IMyClass, ThidClass>("Third");

// Resolve a collection of the mapped target objects
IEnumerable<IMyClass> myClassInstances = resolver();
' Create a Unity container
Dim myContainer As IUnityContainer = New UnityContainer()

' Create an IEnumerable resolver for the IMyClass interface type
Dim resolver = myContainer.Resolve(Of Func(Of IEnumerable(Of IMyClass)))()

' ... other code here...

' Register mappings for the IMyClass interface to appropriate concrete types
myContainer.RegisterType(Of IMyClass, FirstClass)("First")
myContainer.RegisterType(Of IMyClass, SecondClass)("Second")
myContainer.RegisterType(Of IMyClass, ThidClass)("Third")

' Resolve a collection of the mapped target objects
Dim myClassInstances As IEnumerable(Of IMyClass) = resolver()

You can also use the deferred resolver to resolve instance registrations. For example, the following code shows how you can resolve an IEnumerable collection of string values.

// Create a Unity container
IUnityContainer myContainer = new UnityContainer();

// Create an IEnumerable resolver for string instance registrations
var resolver = myContainer.Resolve<Func<IEnumerable<string>>>();

// ... other code here...

// Register mappings for the IMyClass interface to appropriate concrete types
myContainer.RegisterInstance("one", "FirstString");
myContainer.RegisterInstance("two", "SecondString");
myContainer.RegisterInstance("three", "ThirdString");

// Resolve a collection of the strings
IEnumerable<string> myStringInstances = resolver();
' Create a Unity container
Dim myContainer As IUnityContainer = New UnityContainer()

' Create an IEnumerable resolver for string instance registrations
Dim resolver = myContainer.Resolve(Of Func(Of IEnumerable(Of String)))()

' ... other code here...

' Register mappings for the IMyClass interface to appropriate concrete types
myContainer.RegisterInstance("one", "FirstString")
myContainer.RegisterInstance("two", "SecondString")
myContainer.RegisterInstance("three", "ThirdString")

' Resolve a collection of the strings
Dim myStringInstances As IEnumerable(Of String) = resolver()

Next Topic | Previous Topic | Home | Community