【问题标题】:Create an object knowing only the class name?创建一个只知道类名的对象?
【发布时间】:2010-09-22 17:08:08
【问题描述】:

我有一组课程,每个课程都是不同的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

如何在仅配置类名时使其工作?将命名空间连接到类名以获得完整类型名?是否还有另一个有效的反射调用?

如果您认为这是无用的,并且我应该期望配置包含完整的类型名称,我愿意接受该解决方案!只需提供理由来说服我。

(我不会从这个程序集/命名空间之外加载类型)

【问题讨论】:

  • 我可以只使用 IoC 容器,处理长名称,然后为我完成对象创建!

标签: c# .net reflection configuration


【解决方案1】:
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails

也可能是由于 CreateInstance 不返回 BaseClass 的实例,而不是包装到 ObjectHandle 中的 BaseClass 的实例。

在您使用 UnWrap 方法后将其转换为您的 BaseClass。

【讨论】:

    【解决方案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;
    }
    

    【讨论】:

      【解决方案3】:

      由于您知道所有类都来自同一个命名空间,因此配置一次并使用它:

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

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

      【讨论】:

      • 感谢有关程序集加载的答案、代码和讨论。但我喜欢 Bryan 对配置的关注(因为我无法摆脱完整的类型名称)。
      【解决方案4】:
      (我不会从这个程序集/命名空间之外加载类型)

      由于上面的行,可以安全地假设您知道命名空间是什么。你不能这样做吗:

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

      如果您希望将来能够添加要加载的其他策略类,也许通过额外的程序集,您将需要完全限定您的类名。无论如何都建议这样做,因为您将能够为您的应用程序提供增强的可扩展性。

      【讨论】:

      • 这实际上取决于该代码的位置(以及您如何解释“从外部” - 即那是类?还是调用者?)。如果没有程序集限定名称,Type.GetType(string) 将查看当前程序集和一些系统程序集。它不会在随机引用的 dll 中找到类型。
      【解决方案5】:

      要么使用程序集限定名称,要么获取程序集并使用Assembly.GetType(name)。在这种情况下,由于您需要配置文件中的类型,因此程序集限定是一种有效的方法 - 但因为您知道所有类型都在同一个程序集中:

      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) 具有经常引起混淆的探测规则...它查看调用程序集和一些系统程序集 - 但不是所有已加载的程序集。

      【讨论】:

      • 我有一个服务引用,我想使用它来调用它,但它不会出现在程序集的类型列表中(由类制成)。即使我可以通过调用构造函数硬代码来创建引用的对象。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-29
      • 1970-01-01
      • 1970-01-01
      • 2021-12-15
      • 2012-12-17
      • 2016-04-13
      相关资源
      最近更新 更多