Activator.CreateInstance()麻烦

时间:2009-09-27 21:50:46

标签: c# class instantiation activator

我有一个工厂应该创建在运行时从类Foo继承的对象。我认为System.Activator.CreateInstance的返回类型与它创建的对象的类型相同,但从以下错误消息判断,它的返回类型是Object。

  

错误1无法将类型'object'隐式转换为'cs_sandbox.Foo'。存在显式转换(您是否缺少演员?)F:\ projects \ cs_sandbox \ Form1.cs 46 24 cs_sandbox

好的,也许我错过演员,但是

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

会导致另一条错误消息 - 我必须承认 - 这对我没有意义:

  

错误1找不到类型或命名空间名称't'(您是否缺少using指令或程序集引用?)F:\ projects \ cs_sandbox \ Form1.cs 45 25 cs_sandbox

这是我的代码:

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);
        }
    }
}

如何修复此代码?或者,如果它不可修复,那么在运行时创建从特定类继承的对象的其他方法是什么?

6 个答案:

答案 0 :(得分:11)

您需要将返回的对象强制转换为Foo类型。将它强制转换为变量中定义的类型是没有意义的。它应该由编译器知道,因为通过继承层次结构的整个点是满足编译器的静态类型检查。

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

有一个通用版本System.Activator.CreateInstance<T>,它创建一个已知类型(不是类型变量,但是类型参数或静态已知类型,在后一种情况下,它没有多大意义):< / p>

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

答案 1 :(得分:2)

我必须在激活后使用UnWrap()方法,如MSDN上所述:

// Creates an instance of MyType defined in the assembly called ObjectHandleAssembly.
ObjectHandle obj = domain.CreateInstance("ObjectHandleAssembly", "MyType");

// Unwrapps the proxy to the MyType object created in the other AppDomain.
MyType testObj = (MyType)obj.Unwrap();

如上所述on MSDN。此外,我不得不使用这样的参数:

    ObjectHandle obj = domain.CreateInstance("Other.Assembly.Name", "Full.Class.Namespace.ClassName");

答案 2 :(得分:1)

更改代码后

只需将结果投放到Foo

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

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

第一个更健壮,因为在不可能的情况下你不会得到异常。它只会返回null。但这取决于你想要的东西。

更改代码之前

您是否尝试过泛型?

public static OutType CreateInstance<OutType>(string s)
{
    Type t;
    if (s.StartsWith("abcdef"))
    {
        t = typeof(Bar);
        return System.Activator.CreateInstance(t) as OutType;
    }
    else
    {
        t = typeof(Meh);
        return System.Activator.CreateInstance(t) as OutType;
    }
}

但你确实遇到了问题。在您现有的静态方法中,您尝试以任何方式返回与Bar无关的MehFoo。除非您的方法还返回一个对象或一个共同的祖先类型(如在转换中),否则这将始终是一个例外。

要控制更多内部类型,您可以定义方法在内部使用的多个泛型类型。

答案 3 :(得分:0)

我认为你应该这样做:

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

我的观点是,在此代码中,CreateInstance方法没有直接引用包含FooChild1和FooChild2的程序集。在原始代码中,您通过显式命名FooChild1和FooChild2来创建一个类型,因此您可能只是新建它们而不是激活它们。

这对你有意义吗?

答案 4 :(得分:0)

我认为正确的是:

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"));
   }
}

希望能帮到你

答案 5 :(得分:0)

也许有点晚但如果我不知道类型(如果你构建自己的代码分析器)我使用Convert.ChangeType

  string original = "1";
  object value;
  value = Convert.ChangeType(original, typeof(int));

typeof(int)可以是使用object.GetType();

的任何您不知道的类型