Partager via


Configuration Support for Generics

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

The latest Unity Application Block information can be found at the Unity Application Block site.

The following sections of this topic describe the Unity Application Block configuration support for generic parameters and arrays in more detail:

  • Configuration Support for Generic Parameters
  • Configuration Support for Generic Arrays

Configuration Support for Generic Parameters

Unity generic parameter injection configuration support for params and properties is provided by the GenericParameter class when using the API and by the genericParameterName for injection by using attributes in configuration files.

Unity always resolves closed generics. There are two ways to configure them:

  • You can configure injection for a specific closed generic type (and only that type) just as you would configure a non-generic type. In this case, Unity handles closed generics exactly as it handles non-generic types, and configuring injection works just as it does for non-generic types by using parameterType, propertyType and ResolvedParameter, InjectionParameter.
  • You can configure injection on the open generic type and it would apply to any closed generic built from it. In this case, when a closed type is resolved, the actual parameters that had as their type one of the open generic type's generic type parameters are used in the GenericParameter and genericParameterName injection process.

Use GenericParameter for run-time support and to configure injection at the open generic type level. Use the genericParameterName configuration element to support use of a .config file.

For more information about the schema, see Source Schema for the Unity Application Block.

Setting the genericParameterName causes a GenericParameter to be created, using the value for genericParameterName and, optionally, the dependency element's name as the resolutionKey if such a dependency element exists and has a name.

The genericParameterName element is the name of a generic type parameter in the open generic type for which injection is being configured.

The following sections of this topic describe theUnity Application Block support for generic parameters in more detail:

  • Run-Time Support
  • Design-Time Support
  • Generic Decorator Chain

Run-Time Support

Unity generic parameter injection run-time API configuration support for params and properties is provided by the GenericParameter class.

For example, the following code calls a class that takes a generic parameter.

        public class Class1<T>
        {
            public T InjectedValue;
            public Class1(string s, object o)
            {
            }
            public Class1(T injectedValue)
            {
                InjectedValue = injectedValue;
            }
        }

The following code calls the configuration constructor.

        public void CallConstructorTakesGeneric()
        {
            IUnityContainer container = new UnityContainer()
                .Configure<InjectedMembers>()
                .ConfigureInjectionFor(typeof (Class1<>),
                                       new InjectionConstructor(new GenericParam("T")))
            Account a = new Account();
            container.RegisterInstance<Account>(a);
            Class1<Account> result = container.Resolve<Class1<Account>>();
            Assert.AreSame(a, result.InjectedValue);
        }

Design-Time Support

Unity generic parameter injection configuration support for params and properties is provided by the genericParameterName attributes in configuration files.

In a configuration file, you would specify the following.

<property name=”MyProperty” genericParameterName=”TProperty”/>

The following XML example shows the use of the genericParameterName in a configuration file. There must be a generic type parameter named T1 in the type mapped to the TGenericType alias.

...
    <typeAliases>
      <typeAlias alias="IGenerics"
         type="AMachine.Unity.Configuration.IGenerics`1,
         AMachine.Unity.Configuration" />
      <typeAlias alias="TGenericType"
         type=" AMachine.Unity.Configuration.ObjectWithOneType`1,
         AMachine.Unity.Configuration" />
    </typeAliases>
    <containers>.

      <container name="AContainer">
        <types>
          <type type="IGenerics" mapTo="TGenericType">
            <typeConfig>
              <constructor>
                <param name="t1Value" genericParameterName="T1">
                  <dependency/>
                </param>
              </constructor>
            </typeConfig>
          </type>
        </types>
      </container>
...
    </containers>

Note

The .NET Framework convention for expressing generic types is ObjectWithOneType1</STRONG>, where the digit following the "<STRONG>" matches the number of types contained in the generic type.

In the following example, ObjectWithOneType contains one type.

<typeAlias alias="TGenericType"
         type="Tests.Unity.Configuration.ObjectWithOneType`1,
         Tests.Unity.Configuration" />
 In the following example ObjectWithOneType contains four types.
<typeAlias alias="TGenericType"
         type="Tests.Unity.Configuration.ObjectWithOneType`4,
         Tests.Unity.Configuration" />

For more information about generic array support, see Configuration Support for Generic Arrays.

Configuration error exceptions, such as ConfigurationErrorException, are thrown for the following conditions:

  • Both Type and genericParameterName are set.
  • Neither Type nor genericParameterName are set.
  • An injection value other than <dependency> is specified and the genericParameterName is set.
  • A <dependency> element with a value for type is specified and the genericParameterName is set.

Support for Generic Decorator Chains

Support for generic decorator chains is provided by the generic parameter.

The following code example uses a generic decorator.

public interface IRepository<T, TID> {
    T Get(TID id);
}
public class RepositoryBase<T, TID> : IRepository<T, TID> {
  public T Get(TID id) {
    return default(T);
  }
}
public class LoggingRepositoryDecorator<T, TID> : IRepository<T, TID>
{
private IRepository<T, TID> _inner;
public LoggingRepositoryDecorator(IRepository<T,TID> inner)

{
_inner = inner;
}
public T Get(TID id)
{
return _inner.Get(id);
}
}

The following code example uses the generic decorator. The example uses the classes defined in the preceding example.

public void CreateADecoratedIRepository()
{
    IUnityContainer container = new UnityContainer()
        .RegisterType(typeof(IRepository<,>), typeof(LoggingRepositoryDecorator<,>), "logging")
        .RegisterType(typeof(IRepository<,>), typeof(RepositoryBase<,>));

    container.Resolve<IRepository<string, int>>("logging");
}

Configuration Support for Generic Arrays

Support is provided for generic parameter arrays in both configuration files and in the API. In configuration files, support is provided by the genericParameterName attribute with the array designator added to the parameter name, as in " genericParameterName T[]". The genericParameterName attribute has the following characteristics:

  • Use the generic parameter name from the configured type's generic type parameters. Specify <property name=”MyProperty” genericParameterName=”T”/>. Using the format <dependency/> is the only available child element. It is optional. The result is a configuration on the container that causes an instance of whatever "T" is in the closed generic type to be resolved based on this open generic configuration.
  • Use the generic parameter name with a "[]" suffix. With this format, <array/> is the only available child element with no elements. This results in a configuration on the container that will ResolveAll() the instances of whatever "T" is in the closed generic type being resolved based on this open generic configuration.

Note

Support is only provided for actual arrays; it is not provided for generic collections of other types.

Generic array resolution support in the API is provided by GenericResolvedArrayParameter, which is used just like the ResolvedArray API, except that it supports the injection of arrays of a generic type.

The following sections of this topic describe the Unity Application Block support for generic parameters at run time and at design time in more detail:

  • Run-Time Support
  • Design-Time Support

Run-Time Support

The following code example is for a class with a generic array parameter.

    public class SupportClass{ }
    public class ClassGeneric<T>
    {
        private T[] arrayProperty;
        public T[] ArrayProperty
        {
            get { return arrayProperty; }
            set { arrayProperty = value; }
        }
        private T[] arrayCtor;
        public T[] ArrayCtor
        {
            get { return arrayCtor; }
            set { arrayCtor = value; }
        }
        public ClassGeneric()
        { }
        // A generic class with an array property
        public ClassGeneric(T[] arrayCtor)
        {
            ArrayCtor = arrayCtor;
        }
    }
'Usage
            Public Class SupportClass
            End Class

    Public Function ClassGeneric(ByVal T As Of) As Class
            get 
            {
             Return arrayProperty
            }
            set 
            {
             arrayProperty = value 
            }
    End Function
        Private arrayCtor() As T
        Public Property ArrayCtor() As T()
        Get 
             Return arrayCtor
        End Get
        Set (ByVal Value As T()) 
             arrayCtor = value
        End Set
        End Property
        <InjectionConstructor> _ 
        Private Function ClassGeneric() As Public
        End Function

        Private Function ClassGeneric(ByVal arrayCtor() As T) As Public
            ArrayCtor = arrayCtor
        End Function
    End Class

Programmatically configure injection, as shown in the following code.

        public void ConfigureGenericInjection()
        {
            IUnityContainer container = new UnityContainer();

            container.Configure<InjectedMembers>()
                .ConfigureInjectionFor(typeof(ClassGeneric<>),
                    new InjectionProperty("ArrayProperty", new GenericResolvedArrayParameter("T"))
                );

            ClassGeneric<SupportClass> resolved = container.Resolve<ClassGeneric<SupportClass>>();

        }
'Usage
Public  Sub ConfigureGenericInjection()
            Dim container As IUnityContainer =  New UnityContainer() 
 container.Configure(Of InjectedMembers)()
                .ConfigureInjectionFor(Type.GetType(ClassGeneric(Of T)),
                    New InjectionProperty("ArrayProperty", New GenericResolvedArrayParameter("T"))
                )



        End Sub

Design-Time Support

The following configuration XML specifies a generic array by using the genericParameterName attribute with the array designator, "[]". The example then specifies two instances of the generic array.

      <container name="populatedArrayForProperty">
        <types>
          <type type="ILogger" mapTo="MockLogger" name="log1">
            <lifetime type="singleton" />
          </type>
          <type type="ILogger" mapTo="SpecialLogger" name="log2">
            <lifetime type="singleton" />
          </type>
          <type type="GenericArrayProperty">
            <typeConfig>
              <property name="Values" genericParameterName="T[]">
                <array>
                  <dependency name="log1"
                  <dependency name="log2"
                </array>
              </property>
            </typeConfig>
          </type>
        </types>
      </container>