Specifying Types in the Configuration File
This topic explains how to use types in Unity configuration files. At the core of Unity's functionality are types and how you specify and handle them. You will need to specify types many times in the typical configuration file. The configuration files have their own set of rules for writing type names—rules that differ from those for types written in C# or Visual Basic. These rules apply everywhere you can specify a type in the Unity configuration section.
This topic contains the following section that describe how you can specify types:
- CLR Type Names
- Type Aliases
- Automatic Type Lookup
- Default Aliases and Assemblies
- Generic Types
CLR Type Names
You can specify a type name by using the CLR standard type name syntax, as shown in the following example:
<namespace>.<typename>, <assembly>
You can use either partial assembly names or fully qualified assembly names which include the culture, version, and public key token. These names are straightforward for simple types.
In order to specify a name for a type that is in the global assembly cache, you must use the fully qualified assembly name for the type to be correctly loaded. For example, for System.String, a type in mscorlib, you cannot use System.String, mscorlib. You must use the fully qualified assembly name, System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.
CLR type names can be very verbose, especially when working with generic types. For example, compare the following simple dictionary in C# or Visual Basic with the CLR example:
Dictionary<string, int>
Dictionary(Of String, Integer)
System.Collections.Generic.Dictionary`2[[System.String, mscorlib, 2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089], [System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
In order to expedite the process and make type names less error prone, Unity configuration provides two options you can use in the configuration file: aliases and automatic type lookup.
Type Aliases
An alias is simply a shorthand name that will be replaced with the full type name when configuration is applied to the container. You specify an alias in the configuration file inside the section, but outside any <container> elements, as shown in the following example:
<unity xmlns="https://schemas.microsoft.com/practices/2010/unity">
<alias alias="MyAlias" type="full type name" />
...
</unity>
There are the following rules for using aliases:
- You can have an arbitrary number of <alias> elements in the configuration file.
- Anywhere you can give a type name you can use an alias instead.
- There are no recursive aliases, which means that you cannot use an alias to define the type for an alias.
- Alias names are case sensitive: <alias alias="int" /> and <alias alias="Int" /> are two different aliases and are not interchangeable.
Note
Aliases only exist at configuration time. They are not available at run time.
Automatic Type Lookup
In many cases, like for ILogger in the Format of the Unity Configuration File example, the name of a type is all that is required. But given Unity's dependence on types and the large number of types typically involved in a configuration, the ability to perform automatic type lookups further expedites the process. By incorporating automatic type lookups, Unity also eliminates the need to define an alias for every type in an assembly, which saves effort and serves to reduce the chance for error from repeatedly typing the namespace and assembly name.
The Unity configuration system can search for types. However, it will only look for types if the type name specified is not a full type name and it is not an alias. You can provide the configuration section with the namespaces and assemblies to look through by using the <namespace> and <assembly> elements, as shown in the following example.
<unity xmlns="https://schemas.microsoft.com/practices/2010/unity">
<namespace name="MyApp.Interfaces" />
<namespace name="System" />
<assembly name="MyApp” />
<assembly name="mscorlib, 2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
...
</unity>
With the configuration shown in the previous example, when the configuration system hits a name it does not recognize as a type name or alias, it will then search through the assemblies and namespaces for a match. So, to find ILogger, it will try to match the following names in order:
- MyApp.Interfaces.ILogger, MyApp
- System.ILogger, MyApp
- MyApp.Interfaces.ILogger, mscorlib, 2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- System.ILogger, mscorlib, 2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
The search will stop at the first matching type.
The system uses simple string concatenation to create the type name it attempts to load. However, you cannot specify a namespace qualified name plus the type, MyApp.Interfaces.ILogger, MyApp, if you have any namespace elements in your configuration section, <namespace name="System" />.The namespace from the configuration section will be appended to the namespace, resulting in a search on the wrong name, System.MyApp.Interfaces.ILogger. You should put namespaces in the <namespace> elements instead of on the type names in the configuration file to avoid this possibility.
If you have a large number of assemblies and namespaces, then the system type search could take a significant amount of time to complete. Normally, containers are only configured at application startup, so this time hit will not be significant during the operation of your application. If you find it becomes a significant issue, then you should consider using an explicit alias for the types that take the greatest search times, since aliases are matched first.
When matching a name with a type, the configuration system performs the following steps in order. The first one to succeed stops the process:
- Attempt to load a type using the name directly (treated as a full type name)
- Attempt to match a name to an alias
- Do automatic type search
Default Aliases and Assemblies
Some types and assemblies are used frequently in Unity configuration files. The Unity configuration system provides a set of predefined default aliases so you do not have to explicitly add aliases for these common types. Any user-defined entries will overwrite the default ones.
Note
Aliases are case sensitive.
In addition to the default aliases, the Unity configuration system also automatically adds System and mscorlib assemblies to the list of assemblies that are searched for types.
The following table has the complete list of pre-defined type aliases provided by Unity:
Default Alias |
Type |
---|---|
sbyte |
System.SByte |
short |
System.Int16 |
int |
System.Int32 |
integer |
System.Int32 |
long |
System.Int64 |
byte |
System.Byte |
ushort |
System.UInt16 |
uint |
System.UInt32 |
ulong |
System.UInt64 |
float |
System.Single |
single |
System.Single |
double |
System.Double |
decimal |
System.Decimal |
char |
System.Char |
bool |
System.Boolean |
object |
System.Object |
string |
System.String |
datetime |
System.DateTime |
DateTime |
System.DateTime |
date |
System.DateTime |
singleton |
Microsoft.Practices.Unity.ContainerControlledLifetimeManager |
ContainerControlledLifetimeManager |
Microsoft.Practices.Unity.ContainerControlledLifetimeManager |
transient |
Microsoft.Practices.Unity.TransientLifetimeManager |
TransientLifetimeManager |
Microsoft.Practices.Unity.TransientLifetimeManager |
perthread |
Microsoft.Practices.Unity.PerThreadLifetimeManager |
PerThreadLifetimeManager |
Microsoft.Practices.Unity.PerThreadLifetimeManager |
external |
Microsoft.Practices.Unity.ExternallyControlledLifetimeManager |
ExternallyControlledLifetimeManager |
Microsoft.Practices.Unity.ExternallyControlledLifetimeManager |
hierarchical |
Microsoft.Practices.Unity.HierarchicalLifetimeManager |
HierarchicalLifetimeManager |
Microsoft.Practices.Unity.HierarchicalLifetimeManager |
resolve |
Microsoft.Practices.Unity.PerResolveLifetimeManager |
perresolve |
Microsoft.Practices.Unity.PerResolveLifetimeManager |
PerResolveLifetimeManager |
Microsoft.Practices.Unity.PerResolveLifetimeManager |
Generic Types
The CLR type name syntax for generic types is extremely verbose, and it also does not allow for things like aliases. The Unity configuration system allows for a shorthand syntax for generic types that also allows for aliases and type searching.
To specify a closed generic type, you provide the type name followed by the type parameters in a comma-separated list in square brackets.
The Unity shorthand would look like the following example.
<container>
<register type="IDictionary[string,int]" </register>
</container>
If you wish to use an assembly name-qualified type as a type parameter, rather than an alias or an automatically found type, you must place that entire name in square brackets, as shown in the following example:
<register type="IDictionary[string, [MyApp.Interfaces.ILogger, MyApp]]"/>
To specify an open generic type you simply leave out the type parameters. You have two options:
- Use the CLR notation of `N where N is the number of generic parameters.
- Use the square brackets, with commas, to indicate the number of generic parameters.
Generic Type |
Configuration file XML using CLR notation |
Configuration file XML using comma notation |
---|---|---|
IList<T> |
IList`1 |
IList[] |
IDictionary<K,V> |
IDictionary`2 |
IDictionary[,] |