Abstract Classes and Generic Methods

I ran into a fun scenario where I passing an object that derived from an abstract base class into a generic static method where it would be passed on to another generic method for some special, type-specific processing. Everything worked great when I passed in an object declared as one of the derived types. However, when the object was declared as the abstract base type, it all fell apart because the generic method wanted to treat the object as the base type and not the actual, derived type!

Problem

Consider this re-invented version of the scenario. I have a static PatientRouter class that accepts injured Creatures. If the Creature is a Human, it will be routed to a HumanHospital. If it’s an Animal, it will be routed to an AnimalHospital. Note, however, that the code fails if a Creature object is received, even if the Creature is actually a Human or Animal. We need to do something so this Creature can be correctly cared for!

public static class PatientRouter
{
    public static void Route<T>(T creature) 
        where T : Creature
    {
        SendToHospital(creature);
    }

    public static void SendToHospital<T>(T creature)
        where T : Creature
    {
        if (typeof(T) == typeof(Creature))
        {
            throw new Exception("Unacceptable!");
        }
        if (typeof(T) == typeof(Human))
        {
            var h = new HumanHospital();
            h.CareFor(creature as Human);
        }
        if (typeof(T) == typeof(Animal))
        {
            var h = new AnimalHospital();
            h.CareFor(creature as Animal);
        }
    }
}

Solution

There are two options that I found for dealing with this scenario. The first is to use the dynamic keyword introduced in .NET Framework 4.0. Here’s what that might look like:

public static void Route<T>(T creature)
    where T : Creature
{
    dynamic d = creature;
    SendToHospital(d);
}

Unfortunately, .NET 4.0 wasn’t an option for me, though. I was, however, able to come up with an acceptable solution using reflection. I don’t love using reflection to execute a method like this, but it gets the job done–so I’m content to use it in a scenario like this until .NET 4.0 becomes available.

public static void Route<T>(T creature) 
    where T : Creature
{
    // using reflection
    typeof(PatientRouter)
        .GetMethod("SendToHospital")
        .MakeGenericMethod(creature.GetType())
        .Invoke(null, new[] { creature });
}

For reference, here’s the complete example with both solutions:

namespace samples.BaseClassGenericMethod
{
    using System;

    public abstract class Creature
    {
        public bool IsInjured { get; set; }
    }

    public class Human : Creature
    {
        /* human stuff */
    }

    public class Animal : Creature
    {
        /* animal stuff */
    }

    public interface IHospital<T> where T : Creature
    {
        void CareFor(T patient);
    }

    public class HumanHospital : IHospital<Human>
    {
        public void CareFor(Human patient)
        {
            Console.WriteLine("Caring for human!");
        }
    }

    public class AnimalHospital : IHospital<Animal>
    {
        public void CareFor(Animal patient)
        {
            Console.WriteLine("Caring for animal!");
        }
    }

    public static class PatientRouter
    {
        public static void Route<T>(T creature) 
            where T : Creature
        {
            // base case
            SendToHospital(creature);

            // using dynamic (.NET 4.0)
            //dynamic d = creature;
            //SendToHospital(d);

            // using reflection
            //var h = typeof(PatientRouter)
            //    .GetMethod("SendToHospital")
            //    .MakeGenericMethod(creature.GetType())
            //    .Invoke(null, new[] { creature });
        }

        public static void SendToHospital<T>(T creature)
            where T : Creature
        {
            if (typeof(T) == typeof(Creature))
            {
                throw new Exception("Unacceptable!");
            }
            if (typeof(T) == typeof(Human))
            {
                var h = new HumanHospital();
                h.CareFor(creature as Human);
            }
            if (typeof(T) == typeof(Animal))
            {
                var h = new AnimalHospital();
                h.CareFor(creature as Animal);
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var h = new Human();
            PatientRouter.Route(h);

            var a = new Animal();
            PatientRouter.Route(a);

            Creature c = new Human();
            PatientRouter.Route(c);

            Console.ReadLine();
        }
    }
}

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);
		}
	}
}