views:

440

answers:

3

I have a foreach loop that cycles through a list of types and creates an instance of each one. However, when I build, it gives a CS0246 error ("The type or namespace could not be found ... "). Here's a simplified version of the code:

internal static class TypeManager
{
    internal static void LoadTypes()
    {
        // Fill the list with types

        // Create instances of each type
        foreach (Type currType in Types)
        {
            Type aType = currType; // comiles fine
            Object newObj = (currType)Activator.CreateInstance<currType>; // CS 0246
        }
    }

    public static List<Type> Types;
}

Edit: Follow-up question

My foreach loop now looks like this:

foreach (Type currType in Types)
{
    Types.Add((Type)Activator.CreateInstance(currType));
}

with Types List now being of type Object

This compiles fine, but when I run it, I get the following:

Object reference not set to an instance of an object.

If I break this up into two lines that first creates an object then adds it to the List, the first line is fine (the object is created successfully), but it gives me the same error message.

Edit: Update code sample

internal static LoadPlugins()
{
    foreach (Type currType in pluginAssembly.GetTypes())
    {
        if (typeof(IPlugin).IsAssignableFrom(currType))
        {
            Assembly.LoadFrom(currFile.FullName);
            Object pluginInstance = Activator.CreateInstance(currType); // Compiles and runs fine
            Plugins.Add((IPlugin)pluginInstance); // NullReferenceException
            break;
        }
    }
}

public static List<IPlugin> Plugins;
+4  A: 

Generics have to be known at compile time. You can't pass in a type that's determined at run time.

So you can do this:

(SomeType)Activator.CreateInstance<SomeType>;

but you can't do this:

(currType)Activator.CreateInstance<currType>;
Joseph
Good to know about generics. I ended up changing to the non-generic CreateInstance() method (as suggested by dtb below).
Tim
+4  A: 

currType is a variable, not a type variable, so you have to use the non-generic overload:

Object newObj = Activator.CreateInstance(currType);
                                        ^        ^
dtb
Thanks! That did the trick!
Tim
+1  A: 

For the follow-up: it seems you are confused by the difference between the concepts 'Generics' and 'Reflection', you might want to read up on both.

As for your followup question: you are casting the result of Activator.CreateInstance to System.Type, while in fact you should be casting to the actual type. If you want to cast back to the actual type, you need additional runtime checking.

Maybe this code can help you understand:

  var types = new List<Type>
    {
      typeof (string),
      typeof (DateTime)
    };

  foreach (Type t in types)
  {
    // creates an object of the type represented by t
    object instance = Activator.CreateInstance(t);

    // this would cause an InvalidCastException, since instance is not of type 
    // System.Type, but instead either of type System.String or System.DateTime
    // Type t2 = (Type) instance;

    // to cast back to the actual type, additional runtime checks are needed here:

    if (instance is System.String)
    {
      string s = (string) instance;
    }

    else if (instance is DateTime)
    {
      DateTime d = (DateTime) instance;
    }
  }
jeroenh
Thanks for the reply. I don't think I am as far off as it appears. In simplifying the code and working from my original question, I have messed up something. The difference between what you have and what I want is that I want to create a list with an instance of each object. So in the foreach loop, I create a new instance of the object (which works fine), but when I add it to the list<object>, I get a runtime error saying that the object is null. Ironically, I can examine the object in the Locals window and see that it is not null. This may be due to my reading the types at runtime.
Tim
Can you correct the code sample then? As it is now, the following can never work: (Type)Activator.CreateInstance(currType);You're casting to System.Type, while the result of Activator.CreateInstance is not of that type.
jeroenh
Updated the code in the original question. The big picture is that this loads plugins for an application. It searches for *.dll's then checks for types that implement an interface. Then it should create an instance of the type (the plugin) and add it to a List<IPlugin> of plugins. This last step is what is in the code sample.
Tim
The only possibility from what I see in the updated code is that you don't actually create the List<IPlugin>, so Plugins itself is null.
jeroenh