views:

203

answers:

2

I have an abstract generic class BLL<T> where T : BusinessObject. I need to open an assembly that contains a set of concrete BLL classes, and return the tuples (businessObjectType, concreteBLLType) inside a Dictionary. There is the part of the method I could do until now, but I'm having problems to discover T.

protected override Dictionary<Type, Type> DefineBLLs()
{
   string bllsAssembly = ConfigurationManager.AppSettings["BLLsAssembly"];

   Type[] types = LoadAssembly(bllsAssembly);

   Dictionary<Type, Type> bllsTypes = new Dictionary<Type, Type>();

   foreach (Type type in types)
   {
     if (type.IsSubclassOf(typeof(BLL<>)))
        /* how to know T in the situation below? */
        bllsTypes.Add(??businessObjectType (T)??, type);
   }

   return bllsTypes;
}
+3  A: 

So the concrete classes will be closed rather than generic? Here's a short program which demonstrates what I think you're after...

using System;
using System.Reflection;

public abstract class Base<T>
{
}

public class Concrete : Base<string>
{
}

class Test
{
    static void Main()
    {
        Type type = typeof(Concrete);
        Type baseType = type.BaseType;
        Type typeOfT = baseType.GetGenericArguments()[0]; // Only one arg
        Console.WriteLine(typeOfT.Name); // Prints String
    }
}

Note that here I'm assuming that we only need to go up one level to get to the appropriate base type, and that the concrete class will be closed. You'd want to put more checks into your real code, of course, but I suspect it was the call to GetGenericArguments that you were missing.

Jon Skeet
A: 

Jon, that is exactly what I was looking for. I use the basics of reflection and generics, so when it is needed a more profound knowledge of the API to confront both, I miss things like this one, thanks for answering.

Your assumptions are right, the concrete classes are closed, and T is defined on the base class (BLL).

The code became into this:

protected override Dictionary<Type, Type> DefineBLLs()
{
   string bllsAssembly = ConfigurationManager.AppSettings["BLLsAssembly"];

   Type[] types = LoadAssembly(bllsAssembly);

   Dictionary<Type, Type> bllsTypes = new Dictionary<Type, Type>();

   foreach (Type bllType in types)
   {
     if (bllType.IsSubclassOf(typeof(BLL<>)))
     {
        Type baseType = bllType.BaseType;
        Type businessObjectType = baseType.GetGenericArguments()[0];
        bllsTypes.Add(businessObjectType, bllType);
     }
   }

   return bllsTypes;
}
Victor Rodrigues
I'd at least add a comment saying: "This will break if we have any deeper class hierarchies!" Just so you know what's wrong when it goes bang :)
Jon Skeet
Ok Jon, in my case BLL is at the same time the immediate base class from the concrete ones and BLL itself doesn't use inheritance ;)
Victor Rodrigues