【问题标题】:Assembly.CreateInstance to resolve IoC ContainerAssembly.CreateInstance 解析 IoC 容器
【发布时间】:2014-08-07 01:37:09
【问题描述】:

我正在尝试使用以下代码创建一个类的实例(在运行时通过字符串):

Assembly assembly = Assembly.GetAssembly(typeAssembly);
object instance = assembly.CreateInstance(typeName); //throws MissingMethodException
Type classType = instance.GetType();

但是,我尝试实例化的类在构造函数中有两个参数,由 Unity IoC 容器解析。

当我执行上述代码时,它会抛出“System.MissingMethodException”。

我在网上搜索过,看来 Assembly.CreateInstance 将无法解决 Unity 依赖注入。

这是一个死胡同还是有办法使用“CreateInstance”方法实例化类并解决 Unity 依赖项?

【问题讨论】:

标签: c# reflection unity-container ioc-container


【解决方案1】:

CreateInstance 可以接收参数,你可以用 ctor 参数这样调用它:

(T)Activator.CreateInstance(typeof(T), param1, param2);

Activator.CreateInstance 不知道您的应用程序中有 IOC 模块。它只是创建一个类型的实例。

现在你有两个选择:

1.没有使用您的 IOC 管理器的激活器创建实例 - 在我看来,这似乎是做事的正确方法,并且可能是您正在寻找的东西。您的 IOC 管理器 (Unity) 在注入所有依赖项时解析类型。

var instance = UnityManager.Resolve(typeName); // UnityManager is a manager that holds your unity container.

2. 使用 Unity 获取 ctor 参数并在不注入的情况下创建实例(激活器 + 简单参数传递)。 您可能不想这样做。我已将其添加为另一个解释示例。

var param1 = UnityManager.Resolve(typeOfParam1); 
var param2 = UnityManager.Resolve(typeOfParam2); 
Assembly assembly = Assembly.GetAssembly(typeAssembly);
object instance = assembly.CreateInstance(typeName, param1,param2);

【讨论】:

  • 如果我无法访问我的容器怎么办?例如,我试图通过类库中的反射实例化一个对象,但根组合驻留在消费者应用程序中。
  • @ShervinShahrdar - 如果您在一个隔离的类库中,为什么需要通过 ioc 容器进行解析(需要在您的应用程序中配置)?似乎您应该使用 Activator.CreateInstance 来避免糟糕的设计和对 IOC 容器的依赖。如果您出于某种原因确实需要解析器,请创建一个接口 IResolver,将其作为依赖项注入您的类库并使用它。使用您的类库的任何人都需要提供 IResolver。
  • 我正在使用 Activator.CreateInstance。考虑这种情况:我有一个名为 ActionActivator 的类,它驻留在我的隔离库中。 ActionActivator 负责根据程序集和类名实例化和执行代码模块。问题是:ActionActivator 通过构造函数接收许多依赖项,并将它们提供给每个激活的操作。我的主要问题是,当我的操作数量增加时,这个依赖项列表会呈指数增长(例如,我将有 30 个操作,每个操作有 6 个依赖项)
  • @ShervinShahrdar - 为 ActionActivator 提供一个 IResolver 作为依赖项。 IResolver 可以有几个实现,因为有一个应用程序将使用 ActionActivator,它将提供解析器。这类似于 Asp.net 解决问题的方式。您为它提供一个 DependecyResolver(它具有 Activator 的默认实现),它使用提供的解析器来解决问题。您的解析器将使用在应用程序级别配置的容器。由于接口破坏了耦合,因此您的类库对 Unity 没有依赖性。
  • 这本质上是一个ServiceLocator,被认为是"Anti-Pattern", isn't it?我也不想强迫我的 API 的消费者使用 IoC 容器。他们可能正在使用Poor man's DI。
【解决方案2】:

嗯,你有两个选择

1) 向 Unity 请求该类的实例。 Unity 必须解决构造函数参数依赖项。你不在乎,因为 Unity 有责任给你一个实例。但是,我猜出于某种原因,Unity 未初始化或不可用。

2) 对于“typeName”,选择一个合适的构造函数,查看依赖关系,自己实例化依赖关系(或者让 Unity 给你依赖的实例),然后调用构造函数,传入每个依赖的实例。

对于许多依赖注入机制,依赖项是自上而下提供的,AFAIK 对于类型在其构造函数中包含对“container.Inject(this)”的调用是不正常的。这种类型将与容器实现耦合,减少依赖是 IOC 的全部内容。

我猜“typeName”一定没有默认构造函数(MissingMethodException)。

【讨论】:

    【解决方案3】:

    或者您可以将参数注入到要创建实例的类中。然后是这样的

            var assembly = Assembly.GetAssembly(assemblyType);
            var type = assembly.GetType(typeName);
            var instance = Activator.CreateInstance(type, parameter1, parameter2);
    

    【讨论】:

      【解决方案4】:

      如果您在某处的静态属性中具有统一性,则可以执行以下操作:

      Assembly assembly = Assembly.GetAssembly(typeAssembly);
      //get the type
      Type classType = assembly.GetType(typeName);
      
      //using a static property
      var instance = YourApp.Unity.Resolve(classType);
      

      【讨论】:

        【解决方案5】:

        死胡同。 Unity 不是 .NET 框架核心的一部分。您如何期望激活器 (CreateInstance) 神奇地知道这一点并调用 unity 方法来解决问题?

        没办法。

        【讨论】:

        • 在 15 分钟的编码中,您可以拥有一个简单的函数,可以递归地解析构造函数参数。这绝对不是死胡同。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-06-26
        • 1970-01-01
        • 1970-01-01
        • 2016-10-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-26
        相关资源
        最近更新 更多