【问题标题】:Achieving DI without 3rd party framework在没有 3rd 方框架的情况下实现 DI
【发布时间】:2012-02-15 16:50:22
【问题描述】:

我正在编写一个插件作为插件架构的一部分。创建插件的方式是通过反射和CreateInstance。因此调用了默认构造函数。这段代码我无法触及,我试图找到一种明智的方式来使用 DI,而无需使用框架。

我相信我有 3 个选择:

i) 穷人的 DI (PMDI)

ii) 工厂模式

iii) TinyIOC 或类似的(一个处理 DI 的 cs 文件)

我开始查看 PMDI,但后来一个依赖项需要另一个依赖项,所以我最终得到了与此类似的东西,这很丑陋并且可能会变得更糟:

public MyMainPluginClass() : this(new Repo(new Logger()))
{

}

public MyMainPluginClass(IRepo repo)
{

}

然后我转向了工厂模式的想法,但找不到任何像样的演示代码。我想我会有这样的东西:

public static FactoryUtility
{
  public static IRepo GetRepo()
  {
    return new Repo(GetLogger());
  }

  public static ILogger GetLogger()
  {
    return new Logger();
  }
}

    public MyMainPluginClass() : this(FactoryUtility.GetRepo())
    {

    }

    public MyMainPluginClass(IRepo repo)
    {

    }

是这样的吗?

然后我遇到了TinyIOC,这是一个完成所有依赖项注册的类,但我相信它需要在类库中没有的 Program.cs 中进行设置。如果有人有任何使用经验,可以这样使用:

    public MyMainPluginClass()
    {
       var container = TinyIoCContainer.Current;
       container.AutoRegister();
       var implementation = container.Resolve<IRepo>();

       MyMainPluginClass(implementation);
    }

    public MyMainPluginClass(IRepo repo)
    {

    }

是否有任何替代方法可以在不使用 3rd 方库的情况下实现 DI,如果没有,可以从上面选择哪种方法?

注意: 上面的代码尚未编译,只是我认为可行的想法。如果它们是有效的方法,请发布更正。

【问题讨论】:

  • 仅供参考;您的第三个代码示例也基本上是糟糕的依赖注入。

标签: c# .net .net-4.0 dependency-injection inversion-of-control


【解决方案1】:

由于您使用的是 .NET 4,您可能需要考虑使用 MEF,因为它内置在框架本身中。这看起来像是相当简单的 DI,MEF 处理得很好,因为它主要用于可扩展性。

详情请见Learn More page on the MEF CodePlex site

【讨论】:

  • 我不能使用 MEF,因为这是具有自己架构的遗留产品
  • @Jon 如果你正在实现 DI 部分,你可以使用任何你想要的东西......主应用程序不会使用它的事实并不重要。
  • 您是否有使用遗留架构寻找使用 MEF 继承某个基类的插件的示例?
  • @Jon 我没有 - 您只需将 [Export] 属性添加到您的实现类,即:[Export(typeof(LegacyProject.BaseClass)] - 然后根据需要在任何地方导入适当的类型。跨度>
【解决方案2】:

最后我选择了 TinyIOC。不幸的是,插件的构造函数在实际启动和运行之前被多次调用。我只是设置了一个布尔值来防止注册被多次调用,因此它允许我简单地自动注册依赖关系然后我们就走了。

public MyMainPluginClass() : this(FactoryUtility.SetupIOC())
{

}

public MyMainPluginClass(IRepo repo)
{

}

public static class FactoryUtility
{
    private static bool Initialized  = false;

    public static IRepo SetupIOC()
    {
        var container = TinyIoCContainer.Current;

        if (!Initialized)
        {
            container.AutoRegister(new[] { Assembly.GetExecutingAssembly() });

            Initialized = true;
        }

        var result = container.Resolve<IRepo>();

        return result;
    }
}

【讨论】:

    【解决方案3】:

    如果我绝对不想向 DI 容器添加依赖项,我喜欢使用我自己的 TinyIOC(对不起这个名字,不知道它被占用了),对于小型项目,它给了我相同的语义与使用容器一样,但时钟低于 200 LOC。

    如果你有兴趣,这里是代码:https://gist.github.com/ad7608e2ae10b0f04229

    【讨论】:

    • 这会在我的默认构造函数中设置,然后我可以调用另一个具有解析类型的构造函数吗?
    • 应用程序的 Ioc 部分通常存在于应用程序的基础架构中。在您的应用程序的某些神经痛点,容器被要求提供一个实例,并且在那一刻解决了依赖关系。上面的代码也有容器的概念。
    • 我同意,但正如我所提到的,我无法触摸原始应用,也没有 program.cs 来设置 IOC 容器
    • 但是有些东西调用了你的代码的某些部分,对吧?从您的角度来看,这将是入口点,从那里您可以使用 Ioc-pieces...
    • 入口点是构造函数。主应用程序使用反射来查找 DLL,如果找到匹配项,它会调用 CreateInstance 来调用构造函数。然后该类可能具有依赖关系,而依赖关系又具有依赖关系。在构造函数中设置 IOC 会起作用吗?
    猜你喜欢
    • 2016-05-19
    • 1970-01-01
    • 1970-01-01
    • 2012-05-28
    • 2016-01-03
    • 2019-07-24
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多