【问题标题】:Two services dependend on eachother (stackoverflow exception) - how to solve?两个相互依赖的服务(stackoverflow异常)——如何解决?
【发布时间】:2013-08-29 07:59:10
【问题描述】:

我是依赖注入的新手,我正在尝试解决一个问题。我有两个服务。这些服务中的每一个都有相互需要的方法。

例如:SiteManager 有需要我的ForumManager 的方法。我的ForumManager 有需要我的SiteManager 的方法。

我有以下两个类

public class SiteManager:ISiteManager
{
    public IForumManager ForumManager { get; set; }

    public SiteManager()
    {
        this.ForumManager = new ForumManager();
    }
}

public class ForumManager:IForumManager
{
    public ISiteManager SiteManager { get; set; }

    public ForumManager()
    {
        this.SiteManager = new SiteManager();
    }
}

很明显这将导致堆栈溢出异常,因为它们相互调用。我在这里阅读了很多帖子,我想我只需要一个关于如何解决这个问题的小提示。我在他们自己的程序集中有我的接口。

我考虑过将依赖项放在它们自己的属性中,这样当它们被使用时,它们就会被制作出来。但是,这是最佳做法吗?

我不使用 IoC 容器(而且我之前没有使用过)。

有关如何以“最佳实践”方式解决此特定问题的任何提示! :-)

【问题讨论】:

  • 一个没有参数实例化的“*Manager”听起来不太可能需要多个实例。您是否考虑过让它们成为单例对象并完全绕过这个问题?
  • 如何使用继承拥有一个包含所有常用方法的管理器类?
  • 听起来你的责任错了。为什么 ForumManager 需要对 SiteManager 的引用?反之亦然?
  • 同意马特戴维的观点。为什么它们相互依赖?

标签: c# design-patterns dependency-injection


【解决方案1】:

你不应该在你的类中调用 new,这会使它们紧密耦合。允许您使用模拟分别测试每个类的 IOC 的正确模式是:-

public class SiteManager:ISiteManager
{
    private readonly IForumManager forumManager;

    public SiteManager(IForumManager forumManager)
    {
        this.forumManager = forumManager;
    }
}

public class ForumManager:IForumManager
{
   private readonly ISiteManager siteManager;

   public ForumManager(ISiteManager siteManager)
   {
      this.siteManager = siteManager;
   }
}

但是,这并不能解决相互递归。解决这个问题的最简单方法是不对其中一个类使用构造函数注入,而是使用属性注入,即将 SiteManager 放回 ForumManager 上的公共属性,并在创建两个对象后设置它。

然后您的设置代码会执行以下操作:-

     IForumManager forumManager = new ForumManager();
     ISiteManager siteManager = new SiteManager(forumManager);
     forumManager.SiteManager = siteManager;

另一种选择是将 ForumManagerFactory 传递给 SiteManager,例如Func<ISiteManager,IForumManager>

     ISiteManager siteManager = new SiteManager((s) => new ForumManager(s));

然后,您可以在站点管理器中调用 Func,传递 this 以获取 IForumManager。 ForumManager 获得 SiteManager 的一个实例,而 SiteManager 拥有 ForumManager 对象。

【讨论】:

  • 最近几天我经常使用您的答案。非常感谢您提供的非常好的答案!
【解决方案2】:

你正在做什么和你所建议的两者都会导致堆栈溢出异常。我不知道你为什么要做这样的事情而且你没有给出任何提示,但我想我可以让你创建一个经理,也许是一个单身人士,也许只是使用静态方法并做:

public static void DoStuff(ISiteManager sm, IForumManager fm)
{
  // your code here can use the best of both without SO
}

而不是在ForumManager 中持有ISiteManagerSiteManager 中的IForumManager

【讨论】:

  • @downvoter 请留言让我知道答案有什么问题
  • 我没有投反对票,但我认为这个解决方案带来的问题多于解决的问题。也许这就是投反对票的原因。
【解决方案3】:

你显然不能有相互依赖的类。您需要做的是创建一个单独的类并将使用相同时间论坛管理器和站点管理器的方法移到那里:这是一个示例 3rd 类:

class ForumAndSiteManager
{
     public ForumAndSiteManager(ISiteManager siteMaanger, IForumManager forumManager)
     {
         //save the injected object to private fileds
     }

     //define methods which will use both sitemanager and forum manager
}

这样你会打破循环依赖

【讨论】:

  • 可以拥有相互依赖的类。
  • 很明显,我的意思是相互依赖的类,正如问题所示,它们在构造函数中相互调用
【解决方案4】:

在将 MVP 与 winforms 和 AutoFac 一起使用时,我遇到了与引用演示者的视图和引用视图的演示者完全相同的问题。我解决它的方法是让你的一个类使用 Initialize 方法将自己传递给另一个类。我不确定这是否是最佳做法,但我之前曾看到过建议 (this question about mvp)

所以对于实现细节:

public class SiteManager:ISiteManager
{
    public IForumManager ForumManager { get; set; }

    public SiteManager()
    {

    }

    public Initialize(IForumManager forumManager)
    {
        ForumManager = forumManager
    }
}

public class ForumManager:IForumManager
{
    public ISiteManager SiteManager { get; set; }

    public ForumManager(ISiteManager siteManager)
    {
        this.SiteManager = new SiteManager();
        this.SiteManager.Initialize(this);
    }
}

编辑实际上可能会与发布的其他解决方案一起使用,我只是纯粹从循环依赖的角度来看这个

【讨论】:

    【解决方案5】:

    你绝对应该避免循环依赖。我的意思是 A 依赖于 B,B 依赖于 A。

    这就像你的context 依赖的癌症。我们使用了 spring.net 框架,它与 java 的版本相反,如果发现这种依赖关系,则无法打开失败的系统。我不得不说,这只会给我们带来混乱和数小时的 spring 日志搜索和分析。

    我们定义了将近 200 个没有任何问题,但是一旦我们添加了 只是另一个 bean 以及 Lazy 引用,它就失败了。现在几乎不可能解开我们的解决方案来避免它,所以我们在它失败时进行钩子和钩子:-(

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-22
      • 2020-01-07
      • 2021-05-12
      • 1970-01-01
      • 1970-01-01
      • 2011-04-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多