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

时间:2008-11-17 17:32:44

标签: c# .net reflection configuration

我有一组课程,每个课程都是不同的strategy来完成同样的工作。

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

选择使用哪种策略是可配置的。我想在app.config文件中只配置类名'ClassB'而不是完整的类型名称'BigCorp.SuperApp.ClassB'。

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

但是,反射调用失败,因为它们需要完整的类型名称,尤其是

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

如何在仅配置类名时才能使其工作?将名称空间连接到完整类型名称的类名?是否有其他反射调用有效?

如果您认为这没用,我希望配置包含完整的类型名称,我对此解决方案持开放态度!只是提供说服我的理由。

(我不会从此程序集/命名空间外部加载类型)

5 个答案:

答案 0 :(得分:18)

使用assembly-qualified-name,或者获取Assembly并使用Assembly.GetType(name)。在这种情况下,既然您需要配置文件中的类型,那么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);

静态Type.GetType(string)具有经常导致混淆的探测规则......它查看调用程序集和一些系统程序集 - 但不是所有已加载的程序集。

答案 1 :(得分:6)

由于您知道所有类都来自同一名称空间,因此请将其配置一次并使用:

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

修改:我将 name 更改为 class ,以更好地表示该属性的含义。

答案 2 :(得分:5)

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

由于上述行,可以安全地假设您知道命名空间是什么。你不能做类似的事情:

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

如果您希望将来可能能够添加其他策略类(可能通过其他程序集),则需要完全限定您的类名。无论如何,这是建议的,因为您可以为您的应用程序提供增强的可扩展性。

答案 3 :(得分:2)

我将使用应用程序配置中的完整类型名称。下面是一个稍微完整但仍然很简单的例子

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

实际创建此

的工厂类
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;
}

答案 4 :(得分:1)

BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails

也可能是因为CreateInstance没有返回BaseClass的实例,而是返回包装在ObjectHandle中的BaseClass实例。

使用UnWrap方法后,将其强制转换为BaseClass。