Home

Castle Stronghold

.Net 2 Generics support

Since the RC3 release, the MicroKernel has support for generic types, which allows you to register generic types bound or not bound to generic arguments. The unbound types will be constructed using the type arguments provided by you or using a clever approach to inherit the arguments.

Warning

Due to a limitation in DynamicProxy (version 1.1.5) an interceptor cannot be associated with a generic type. This limitation was fixed on the new DynamicProxy 2.0 but at the time of writing, it was still unstable to be included in the release.

The Resolve<> method

If you use the Windsor Container compiled for .Net 2.0 you will see that it exposes a Resolve<> method overload that saves you from casting the component instance before using. For example:


// You can use    

IEmailSender sender = container.Resolve<IEmailSender>();

// instead of

IEmailSender sender = (IEmailSender) container[typeof(IEmailSender)];

Registering a generic type with arguments

By "type with arguments" we mean that the generic types are already bound. Consider the following interface and class:


public interface IRepository<T>
{
    T Get(int id);
}

public class Repository<T> : IRepository<T>
{
    public T Get(int id)
    {
        return Activator.CreateInstance<T>();
    }
}

Both are generic types. You can configure them as a component using the standard .Net notation for generic types:


<component 
    id='int.repos.generic' 
    service='Namespace.IRepository`1[[System.Int32]], AssemblyName' 
    type='Namespace.Repository`1[[System.Int32]], AssemblyName' />
    

With the configuration above Windsor will treat the component as an ordinary component. If another component has a dependency on it, it must use the exact same generic arguments. For example:


public class PrimeNumberHolder
{
    private IRepository<int> intRepository;

    public PrimeNumberHolder(IRepository<int> intRepository)
    {
        this.intRepository = intRepository;
    }
}

Registering a generic type without arguments

Continuing to use the example above, we can also register the unbound type. For example:


<component 
    id='int.repos.generic' 
    service='Namespace.IRepository`1, AssemblyName' 
    type='Namespace.Repository`1, AssemblyName' />
    

Now Windsor realizes that in order to create the component instance registered above it needs a generic argument. You can specify the type using the Resolve method or requesting the service with the parameter:


IRepository<Employee> empRepost = 
    container[typeof(IRepository<Employee>)] as IRepository<Employee>;

// or 

IRepository<Employee> empRepost = 
    container.Resolve<IRepository<Employee>>();
    

Guessing the generic argument

Windsor is also able to guess the generic argument. This only happens if the component request dependency is a generic type itself, and the generic types were given for it. All it does is use the same generic types on all dependency requested in the chain. For example, consider the following components:


public class A<T>
{
    public A(B<T> b)
    {
    }
}

public class B<T>
{
    public B()
    {
    }
}

Component A depends on B. Both are generic types. The following configuration snippet registers both without any generic parameter:


<component 
    id='compA' 
    type='Namespace.A`1, AssemblyName' />

<component 
    id='compB' 
    type='Namespace.B`1, AssemblyName' />
    

If you request the component A passing an int as the generic argument, B will be constructed with an int generic argument too:


A<int> componentA = container.Resolve<A<int>>();
    

What if the component A was registered bound to a type?


<component 
    id='compA' 
    type='Namespace.A`1[[System.Int32]], AssemblyName' />

<component 
    id='compB' 
    type='Namespace.B`1, AssemblyName' />
    

This is also supported, and B will be created using the Int32 as the generic argument.

Google
Search WWW Search castleproject.org