Activator.CreateInstance() 的麻烦

发布于 2024-08-05 18:34:41 字数 1047 浏览 12 评论 0原文

我有一个工厂,应该在运行时创建从类 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);
        }
    }
}

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

祁梦 2024-08-12 18:34:41

您需要将返回的对象转换为 Foo 类型。将其转换为变量中定义的类型是没有意义的。编译器应该知道这一点,因为通过继承层次结构进行转换的全部目的是满足编译器的静态类型检查。

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

有一个通用版本,System.Activator.CreateInstance,它创建一个已知类型(不是类型变量,而是类型参数或静态已知类型,在后一种情况下,它不不过很有意义):

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

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>();
深居我梦 2024-08-12 18:34:41

激活后我必须使用 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();

如所述 MSDN 上。此外,我必须使用这样的参数:

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

I had to use to UnWrap() method after activating, like described on 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. Furthermore, I had to use parameters like this:

    ObjectHandle obj = domain.CreateInstance("Other.Assembly.Name", "Full.Class.Namespace.ClassName");
违心° 2024-08-12 18:34:41

更改代码后,

只需将结果强制转换为 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;
    }
}

但是您确实遇到了问题。在现有的静态方法中,您尝试返回与 Foo 没有任何关系的 BarMeh 。这始终是一个例外,除非您的方法还返回一个对象或公共祖先类型(如强制转换)。

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

After you changed code

Just cast your results to Foo like

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. 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. This will always be an exception unless your method also returns an object or a common ancestor type (as in casting).

To control even more internal types you could define more than one generic type that your method would use internally.

臻嫒无言 2024-08-12 18:34:41

我认为您可能应该这样做:

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 创建一个类型,因此您不妨新建它们而不是激活它们。

这对你来说有意义吗?

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?

雪化雨蝶 2024-08-12 18:34:41

我认为正确的是:

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

希望能帮到你

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文