【问题标题】:Cyclic dependency via property injection in Castle Windsor通过 Castle Windsor 中的属性注入实现循环依赖
【发布时间】:2014-07-23 15:06:04
【问题描述】:

我需要 Windsor 中的循环依赖。这是为了递归方法而设计的。模块 A 调用模块 B-F 并且模块 B 需要回调到 A 因为节点树。

无论如何,我知道我不能因此使用构造函数注入。所以我设置了带有属性注入的模块 A 以获得 IEnumerable.

我已经注册了所有类型,但是在解析模块 A 时,Windsor 将属性设置为 Null(我让它抛出异常)。我尝试使用 DependsOn,但这似乎只适用于构造函数参数。

如何让 Windsor 通过属性注入将我的模块 B-F 集合解析为模块 A,以便我可以拥有所需的依赖循环?

这是顶层模块(模块 A)和 IModule;

public interface IModule
{
    bool IsAccessibleToUser(INode node);
}

public class CompositeModule:IModule
{
    private IEnumerable<IModule> innerModules;

    public IEnumerable<IModule> InnerModules
    {
        get { return innerModules; }
        set { 
            if (null == innerModules) throw new ArgumentNullException("innerModules");
            innerModules = value;
        }
    }

    public CompositeModule()
    {
        InnerModules = new List<IModule>();
    }


    public bool IsAccessibleToUser(INode node)
    {
        return innerModules.All(module => module.IsAccessibleToUser(node));
    }

}

还有递归子模块:

public class CheckChildrenModule : IModule
{

    private IModule compositeModule;

    public CheckChildrenModule(IModule compositeModule)
    {

        if (null == compositeModule) throw new ArgumentNullException("compositeModule");

        this.compositeModule = compositeModule;

    }

    public bool IsAccessibleToUser(INode node)
    {

        var attributes = node.Attributes;

        if (!attributes.ContainsKey("checkchildren")) return true;

        string checkchildren = attributes["checkchildren"].ToString();

        if (checkchildren.ToLower() == bool.TrueString.ToLower())
        {
            //look for any child with result of TRUE and stop immediately if found in order to be efficient.
            return node.ChildNodes.Any(childNode => compositeModule.IsAccessibleToUser(childNode));
        }

        return true; //check false or some other value. return true!

    }
}

还有我的注册:

// Configure Windsor to resolve arrays in constructors
container.Kernel.Resolver.AddSubResolver(new ArrayResolver(container.Kernel, true));
//collections too
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));

//other stuff here

container.Register(Component.For<IModule>()
            .ImplementedBy<CompositeModule>()
            .Named("CompositeModule1"));

container.Register(Component.For<IModule>().ImplementedBy<CheckChildrenModule>()
            .DependsOn(ServiceOverride.ForKey<IModule>().Eq("CompositeModule1")));

//A few other IModules here, all of which should be passed to the Composite Module "innerModules" property.

正如我所说,我尝试了似乎不适用于属性的 DependsOn,以及无效的 PropertyRequire,我仍然传递了一个 null。

请注意,我无权访问 Container.Resolve 代码,因为我正在为第 3 方工具注册这些组件。

谢谢!

编辑

我的期望:

  1. Windsor 解析 CompositeModule 并使用默认 ctor 创建一个实例。给它命名。

  2. Windsor 去满足属性,这是 IModules 的可枚举

  3. 它看到 6 个 IModule,不包括 CompositeModule,并尝试将它们实例化为一个集合

  4. 它看到 6 个模块之一 CheckChildrenModule 需要 CompositeModule 的命名实例。

  5. 它使用步骤 1 中创建的 CompositeModule 的命名实例来满足对 CheckChildrenModule 的 ctor 依赖

  6. 现在它可以完成 IModule 的收集,并将它们从第 2 步传递到 CompositeModule 的 InnerModules 属性中。

只是不知道如何让它发生。

【问题讨论】:

  • IModuleInnerModules 属性吗?
  • 没有。 InnerModules 特定于复合模块实现。并非所有模块都具有此层次结构。我将进行编辑以明确这一点。
  • There 你去。
  • 对不起。 “你去吧”是什么意思?
  • 哦。我没注意到这是一个链接!

标签: c# recursion dependency-injection castle-windsor property-injection


【解决方案1】:

我相信您可以使用带有构造函数注入的惰性解析来实现循环依赖。

container.Register(Component.For<ILazyComponentLoader>()
                            .ImplementedBy<LazyOfTComponentLoader>());

public class CompositeModule : ICompositeModule
{
    private IEnumerable<IModule> _childModules;
    public CompositeModule(IEnumerable<IModule> childModules) 
    {
        _childModules = childModules;
    }
}

public class CheckChildrenModule : IModule
{
    private Lazy<ICompositeModule> _compositeModule;
    public CheckChildrenModule(Lazy<ICompositeModule> compositeModule)
    {
        _compositeModule = compositeModule;
    }

    public void DoStuff() 
    {
        _compositeModule.Value.DoStuff();
    }
}

【讨论】:

  • 这不会为 CheckChildrenModule 创建一个新的 ICompositeModule 吗?这只会重新开始循环,因为复合模块需要一个 CheckCHildrenModule 的实例作为其内部之一。此外,传递给 CheckChildrenModule 的 CompositeModule 必须与本身持有对 CheckChildrenModule 的引用的相同。不能是懒惰新建的。
  • 惰性解析将尊重您在注册 ICompositeModule 期间设置的任何生活方式。仅当您将复合材料注册为瞬态时,它才会创建一个新实例(如果您使用任何其他类型的注入也是如此)。
  • 我不熟悉 Windsor 的这种能力。这真的是我需要连接的所有代码吗?如何指定在惰性参数中使用的复合模块的命名实例?另外,由于复合模块必须是第一个注册的 IModule(因此它是首先解析的),我是否需要更改注册中的任何内容以支持这一点?
  • 还有理由将 CompositeModule 切换为 ICompositeModule 而不是 IModule?
  • 成功了。我什至想出了如何对其进行单元测试。如果您能解释您提供的注册的魔力,我会很高兴。懒惰的组件加载器如何在没有我在其他任何地方指定它的情况下进入组合?
猜你喜欢
  • 2023-03-10
  • 1970-01-01
  • 2012-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-21
  • 1970-01-01
相关资源
最近更新 更多