Activator.CreateInstance() troubles

MiseryIndex picture MiseryIndex · Sep 27, 2009 · Viewed 16.2k times · Source

I have a factory that is supposed to create objects that inherit from class Foo at run-time. I would think that System.Activator.CreateInstance's return type was the same as the type of an object it's creating, but judging from the following error message, its return type is Object.

Error 1 Cannot implicitly convert type 'object' to 'cs_sandbox.Foo'. An explicit conversion exists (are you missing a cast?) F:\projects\cs_sandbox\Form1.cs 46 24 cs_sandbox

OK, so maybe I am missing a cast, but

return (t)System.Activator.CreateInstance(t);

results in yet another error message, which -- I must admit -- makes no sense to me:

Error 1 The type or namespace name 't' could not be found (are you missing a using directive or an assembly reference?) F:\projects\cs_sandbox\Form1.cs 45 25 cs_sandbox

And here's my code:

class Foo { }
class FooChild1 : Foo { }
class FooChild2 : Foo { }

class MyFactory
{
    public static Foo CreateInstance(string s)
    {
        Type t;
        if (s.StartsWith("abcdef"))
        {
            t = typeof(FooChild1);
            return System.Activator.CreateInstance(t);
        }
        else
        {
            t = typeof(FooChild2);
            return System.Activator.CreateInstance(t);
        }
    }
}

How can I fix this code? Or, if it's not fixable, what are other ways of creating objects that inherit from a specific class at run-time?

Answer

mmx picture mmx · Sep 27, 2009

You need to cast the returned object to Foo type. It doesn't make sense to cast it to a type defined in a variable. It should be known by the compiler, as the whole point of casting through the inheritance hierarchy is satisfying compiler's static type checking.

return (Foo)System.Activator.CreateInstance(t);

There's a generic version, System.Activator.CreateInstance<T>, which creates a known type (not a type variable but a type argument or a statically known type, in the latter case, it doesn't make much sense though):

return System.Activator.CreateInstance<FooChild1>();