views:

1517

answers:

4

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?

+5  A: 

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>();
Mehrdad Afshari
+1  A: 
Robert Koritnik
A: 

I think you should probably do this:

public static Foo CreateInstance(string objectIdentifer)
{
   if (objectIdentifier == "Child1")
   {
      return (Foo)Activator.CreateInstance("Foo.FooChild1, FooChild1");
   }
   else
   {
      return (Foo)Activator.CreateInstance("Foo.FooChild1, FooChild2");
   }
}

My point is that in this code, the CreateInstance method has no direct reference to the assembly or assemblies containing FooChild1 and FooChild2. In the original code, you create a type by explicitly naming FooChild1 and FooChild2, so you might as well just new them instead of activating them.

Does this make sense to you?

IanT8
A: 

I think the correct is:

public static Foo CreateInstance(string objectIdentifer)
{
   if (objectIdentifier == "Child1")
   {
      return (Foo)Activator.CreateInstance(Type.GetType("Foo.FooChild1, FooChild1"));
   }
   else
   {
      return (Foo)Activator.CreateInstance(Type.GetType("Foo.FooChild1, FooChild2"));
   }
}

Hope that can help you

Thuan DINH