Resolve Generic Types at Runtime with Unity

I’m working on a small project that uses Unity to manage record type-specific data providers. As a brief overview, the project accepts a collection of objects. An appropriate data provider is retrieved for each object, and then the object is passed to that provider for processing.

I register the providers in a UnityContainer like so:

UnityContainer.RegisterType<IDataProvider<RecordType>, RecordTypeDataProvider>();

So, in a perfect world, I wanted to resolve the providers based on the type of each record in a collection. Something like this:

foreach (var record in collection)
{
    var provider = ResolveProvider(record);
    provider.Process(record);
}

The problem with this approach is that I need to resolve the type using the record’s type.

// what I want (invalid)
UnityContainer.Resolve<IDataProvider<record.GetType()>>();

Luckily, there’s a way to do this by using the Type.MakeGenericType method. Check it out:

var providerType = typeof(IDataProvider<>).MakeGenericType(record.GetType());
var provider = UnityContainer.Resolve(providerType);

This works, but it leaves me with another challenge. UnityContainer.Resolve returns an object, but I need an IDataProvider. The solution? A base interface containing the non-generic methods and properties. This allows me to resolve the data provider using the record type but still return a typed object. Here’s the complete solution:

public interface IDataProvider
{
    void Process(BaseType record);
}

public interface IDataProvider<T> : IDataProvider
    where T : BaseType
{
    void Process<T>(T record);
}

public class RecordTypeDataProvider : IDataProvider<RecordType>
{
	// IDataProvider.Process
	public void Process(BaseType record)
	{
		Process(record as RecordType);
	}

	// IDataProvider<RecordType>.Process
	public void Process<RecordType>(RecordType record)
	{
		// process it!
	}
}

public static class Broker
{
	private static readonly UnityContainer UnityContainer;

	static Broker()
	{
		UnityContainer = new UnityContainer();

		UnityContainer.RegisterType<IDataProvider<RecordType>, RecordTypeDataProvider>();
		// other providers...
	}

	private static IDataProvider Resolve(BaseType record)
	{
		var providerType = typeof(IDataProvider<>).MakeGenericType(record.GetType());
		return UnityContainer.Resolve(providerType) as IDataProvider;
	}

	public static void Process(IEnumerable<BaseType> collection)
	{
		foreach (var record in collection)
		{
			var provider = Resolve(record);
			provider.Process(record);
		}
	}
}
Advertisements

Leave a comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s