Tuesday, June 19, 2007

Reflection and Inheritance with Generics

I was working on some SubSonic entities today and I wanted to access some of the properties of the generated classes, not knowing which database objects will exist.

Basically I wanted to write a utility method that would pull out all of the ActiveRecord<T> types in a given assembly.

This was my first attempt:

public static Type[] GetActiveRecordTypes(Assembly assembly)
{
	List<Type> types = new List<Type>();
	foreach (Type type in assembly.GetTypes())
	{
		if(type.IsSubClassOf( typeof(ActiveRecord<__WHAT_GOES_HERE_?__>) )
			types.Add(type);
	}
	return types.ToArray();
}

The part in bold is where I got stuck. Sticking in type there doesn't work. It won't compile.  I wouldn't let that stop me, so I created a temporary solution like this:

if(type.BaseType.Name.Contains("ActiveRecord")) { ... }

This works, but it's a hack and it's brittle. I asked a few friends and Gary DeReese came to my rescue with the following code:

  Type baseType = type.BaseType;
  if(baseType.IsGenericType && 
	baseType.GetGenericType() == typeof(ActiveRecord<>) &&
	baseType.GetGenericParameter()[0] == type) { ... }

It's good to have smart friends you can reach out to in times like this where you just aren't thinking about the problem the way the framework wants you to. Thanks Gary!

Savings - Loans - Savings Accounts - Arizona Landscaping