简体   繁体   English

只知道类名创建一个对象?

[英]Create an object knowing only the class name?

I have a set of classes, each one is a different strategy to do the same work. 我有一组课程,每一个课程都是做同样工作的不同策略

namespace BigCorp.SuperApp
{
    public class BaseClass { }
    public class ClassA : BaseClass { }
    public class ClassB : BaseClass { }
}

The choice of which strategy to use is configurable. 选择使用哪种策略是可配置的。 I want to configure only the class name 'ClassB' instead of the full type name 'BigCorp.SuperApp.ClassB' in the app.config file. 我想在app.config文件中只配置类名'ClassB'而不是完整的类型名称'BigCorp.SuperApp.ClassB'。

<appConfig>
   <SuperAppConfig>
      <Handler name="ClassB" />
   </SuperAppConfig>
</appConfig>

However, the reflection calls fail because they expect the full type name, particularly 但是,反射调用失败,因为它们期望完整的类型名称,尤其是

Type t = Type.GetType("ClassB"); // results in t == null
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails

How can I get this to work while configuring only the class name? 如何在仅配置类名时才能使其工作? Concatenate the namespace to the class name for full type name? 将名称空间连接到完整类型名称的类名? Is there another reflection call that works? 是否有其他反射调用有效?

If you think this is useless and I should expect the configuration to contain the full type name, I am open to that solution! 如果您认为这是无用的,我希望配置包含完整的类型名称,我对该解决方案持开放态度! Just provide rationale to convince me. 只是提供说服我的理由。

(I will not be loading a type from outside this assembly/namespace) (我不会从此程序集/命名空间外部加载类型)

Either use the assembly-qualified-name, or get hold of the Assembly and use Assembly.GetType(name) . 使用assembly-qualified-name,或获取Assembly并使用Assembly.GetType(name) In this case, since you want the types in the config file, assembly-qualified is a valid way to go - but since you know all your types are in the same assembly: 在这种情况下,由于您需要配置文件中的类型,因此assembly-qualified是一种有效的方法 - 但是因为您知道所有类型都在同一个程序集中:

Assembly assembly = typeof(SomeKnownType).Assembly; // in the same assembly!
Type type = assembly.GetType(name); // full name - i.e. with namespace (perhaps concatenate)
object obj = Activator.CreateInstance(type);

The static Type.GetType(string) has probing rules that often cause confusion... it looks at the calling assembly, and a few system assemblies - but not all loaded assemblies. 静态Type.GetType(string)具有经常引起混淆的探测规则......它查看调用程序集和一些系统程序集 - 但不是所有已加载的程序集。

Since you know all classes will be coming from the same namespace, configure it once and use that: 既然您知道所有类都来自同一个命名空间,请配置一次并使用它:

<appConfig>
   <SuperAppConfig handlerNamespace="BigCorp.SuperApp">
      <Handler class="ClassB" />
   </SuperAppConfig>
</appConfig>

Edit: I changed name to class to better denote the meaning of that attribute. 编辑:我将名称更改为以更好地表示该属性的含义。

(I will not be loading a type from outside this assembly/namespace)

because of the above line, it is safe to assume that you know what the namespace is. 由于上面的行,可以安全地假设您知道命名空间是什么。 Couldn't you do something like: 你做不到这样的事情:

Type t = Type.GetType("Namespace." + className); 
BaseClass c = Activator.CreateInstance(t) as BaseClass; 

If you expect to possibly be able to add additional strategy classes to be loaded in the future, perhaps via an additional assembly, you would need to fully qualify your class name. 如果您希望将来可能能够添加其他策略类(可能通过其他程序集),则需要完全限定类名。 This is recommended anyway, since you would be able to provide enhanced extendability for your application. 无论如何,这是建议的,因为您可以为您的应用程序提供增强的可扩展性。

I'm going with the full type name in the application configuration. 我将在应用程序配置中使用完整类型名称。 Below is a slightly more complete, but still trivial example 下面是一个稍微完整但仍然无足轻重的例子

<SuperAppConfig>
   <ObjectConfig provider="BigCorp.SuperApp.ClassA">
      <add name="one" />
      <add name="two" />
   </ObjectConfig>
</SuperAppConfig>

And the factory class that actually creates this 实际创造这个的工厂类

private static Assembly a = typeof(IFactoryObject).Assembly;
public static IFactoryObject CreateObject(String providerName)
{
    Type t = a.GetType(providerName)
    IFactoryObject o = Activator.CreateInstance(t) as IFactoryObject;
    return o;
}
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails

Might also result from the fact, that CreateInstance does not return an instance of BaseClass, rather than an instance of BaseClass wrapped into an ObjectHandle. 也可能是因为CreateInstance没有返回BaseClass的实例,而是返回包装到ObjectHandle中的BaseClass实例。

Cast into your BaseClass after you used the UnWrap method. 使用UnWrap方法后,将其强制转换为BaseClass。

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

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