简体   繁体   English

Activator.CreateInstance()麻烦

[英]Activator.CreateInstance() troubles

I have a factory that is supposed to create objects that inherit from class Foo at run-time. 我有一个工厂应该创建在运行时从类Foo继承的对象。 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. 我认为System.Activator.CreateInstance的返回类型与它创建的对象的类型相同,但从以下错误消息判断,其返回类型是Object。

Error 1 Cannot implicitly convert type 'object' to 'cs_sandbox.Foo'. 错误1无法将类型'object'隐式转换为'cs_sandbox.Foo'。 An explicit conversion exists (are you missing a cast?) F:\\projects\\cs_sandbox\\Form1.cs 46 24 cs_sandbox 存在显式转换(您是否缺少演员表?)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 错误1找不到类型或命名空间名称't'(您是否缺少using指令或程序集引用?)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? 或者,如果它不可修复,那么在运行时创建从特定类继承的对象的其他方法是什么?

You need to cast the returned object to Foo type. 您需要将返回的对象FooFoo类型。 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): 有一个通用版本, System.Activator.CreateInstance<T> ,它创建一个已知类型(不是类型变量,但是类型参数或静态已知类型,在后一种情况下,它没有多大意义):

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

I had to use to UnWrap() method after activating, like described on MSDN: 我必须在激活后使用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();

As described on MSDN . MSDN所述 Furthermore, I had to use parameters like this: 此外,我不得不使用这样的参数:

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

After you changed code 更改代码后

Just cast your results to Foo like 只需将结果投射到Foo就好了

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

or 要么

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

The first one is a bit more robust because you won't get an exception in case cast is not possible. 第一个更健壮,因为在不可能的情况下你不会得到异常。 It will simply return null . 它只会返回null But it depends what you want. 但这取决于你想要什么。

Before you changed code 在更改代码之前

Have you tried generics? 你尝试过泛型吗?

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

But you do have a problem. 但你确实有问题。 In your existing static method you are trying to return Bar and Meh that aren't related to Foo in any way. 在您现有的静态方法中,您试图以任何方式返回与 Foo无关的 BarMeh This will always be an exception unless your method also returns an object or a common ancestor type (as in casting). 除非您的方法还返回一个对象或一个共同的祖先类型(如在转换中),否则这将始终是一个例外。

\n

To control even more internal types you could define more than one generic type that your method would use internally. 要控制更多内部类型,您可以定义方法在内部使用的多个泛型类型。

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. 我的观点是,在此代码中,CreateInstance方法没有直接引用包含FooChild1和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. 在原始代码中,您通过显式命名FooChild1和FooChild2来创建类型,因此您可能只是新建它们而不是激活它们。

Does this make sense to you? 你能理解这个吗?

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 希望能帮到你

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM