tags:

views:

69

answers:

4

I have a dll that contains a number of classes that all inherit from a CommandBase class. I'm trying to get instances of all of these classes (CommandA, CommandB, CommandC, etc...) using reflection in C# so that I can call a specific method on each one. Here is what I have so far:

//get assemblies in directory.
string folder = Path.Combine(HttpContext.Current.Server.MapPath("~/"), "bin");
var files = Directory.GetFiles(folder, "*.dll");
//load each assembly.
foreach (string file in files)
{
  var assembly = Assembly.LoadFile(file);
  if (assembly.FullName == "MyCommandProject")
  {
    foreach (var type in assembly.GetTypes())
    {
      if (!type.IsClass || type.IsNotPublic) continue;
      if(type is CommandBase)
      {
        var command = Activator.CreateInstance(type) as CommandBase;
      }
    }
  }
}

I'm having 2 issues. The 1st issue is that the line "if(type is CommandBase") gives the following warning:

The given expression is never of the provided type CommandBase.

The 2nd issue is that I can't figure out how to get an instance of the actual object (CommandA, CommandB, etc...), just converting it to CommandBase isn't enough.

+1  A: 

That's because your type variable is a Type, not a CommandBase.

You want

if(type == typeof(CommandBase))

(Thanks Greg for the correction)

Andrew Koester
Wouldn't that be `if(type == typeof(CommandBase))`?
Greg
This wouldn't work for derived classes.
Dr. Wily's Apprentice
It ended up being "==" instead of "is" but yeah that worked, thanks. Any advice on my 2nd issue?
Justin
I can tell you it's getting casted as a CommandBase because, well, you're casting it to one, but unfortunately I'm not sure how to cast it to the higher class, since you're getting into a loss of type safety at that point. Usually with something like this, you want to have an interface where you can call the same functions in all of the derived classes.
Andrew Koester
I doubt it will even compile because "Is" expects class name, not type.
Akash Kava
Fixed the is -> == in the answer.
Andrew Koester
+2  A: 

Change type is CommandBase to typeof(CommandBase).IsAssignableFrom(type)

Dr. Wily's Apprentice
+1 You got it right
Jordão
+1 I didnt see your result when I was typing, however this msdn says "If the IsSubclassOf is the converse of IsAssignableFrom. That is, if t1.IsSubclassOf(t2) is true, then t2.IsAssignableFrom(t1) is also true." so we both are equally right, I was pointing towards answers of is and == answers.
Akash Kava
+1  A: 

You must change

if(type is CommandBase) 

to

if(type.IsSubclassOf(typeof(CommandBase)))

If the IsSubclassOf is the converse of IsAssignableFrom. That is, if t1.IsSubclassOf(t2) is true, then t2.IsAssignableFrom(t1) is also true.

Akash Kava
That is, except for my answer, which was correct from the beginning. :), but I'm giving you a +1 for being right and because I've just never noticed the IsSubclassOf method, since I just use IsAssignableFrom.
Dr. Wily's Apprentice
A: 

This is the method I use to load up based on an interface.

private static List<T> GetInstances<T>()
{
        return (from t in Assembly.GetExecutingAssembly().GetTypes()
                where t.GetInterfaces().Contains(typeof (T)) && t.GetConstructor(Type.EmptyTypes) != null
                select (T) Activator.CreateInstance(t)).ToList();
}

And here's the same function that pulls back based on base class.

private static IList<T> GetInstances<T>()
{
        return (from t in Assembly.GetExecutingAssembly().GetTypes()
                       where t.BaseType == (typeof(T)) && t.GetConstructor(Type.EmptyTypes) != null
                       select (T)Activator.CreateInstance(t)).ToList();
}

Of course it would need to be modified slightly to point at the reference you're loading.

Jeff Sheldon
Thanks, but for some reason it only returns the CommandBase class, not classes that inherit from it. Also, if I call it like "GetInstances<CommandBase>()", then it gives me a list of CommandBase objects, not the objects I need - CommandA, CommandB, etc.. It sounds like I need to use interfaces to get this to work.
Justin
Added a second function for you to use for your CommandBase class. You should retrieve a list of instance of classes that inherit from CommandBase. Works when I throw it into a simple snippet test.
Jeff Sheldon
I ended up switching to using interfaces and used your first code example, thanks!
Justin