如何获取 Castle Windsor 中某些依赖项的当前实例化实例的列表?

How to get list of currently instantiated instances of some dependency in Castle Windsor?

假设我有一个组件 Bar 执行 Foo 并通知所有实现 IFooConsumer 接口的服务调用 FooHappened 方法。

我可以这样写Bar

class Bar
{
    public Bar(IEnumerable<IFooConsumer> fooConsumers) { ... }

    public void Foo()
    {
        // foo-ing
        foreach (var f in _fooConsumers) f.FooHappened();
    }
}

它会起作用,但是实例化 Bar 将实例化所有可能的 IFooConsumer。如果我只需要通知在 Foo 发生时存在的那些 IFooConsumer 怎么办?

有没有办法获得某种跟踪器,它知道 IFooConsumer 的所有实例化实例?

我可能可以通过订阅 IWindsorContainer.Kernel.ComponentCreated 自己写一个,但我想知道是否存在类似的东西?或者也许有其他方法可以解决我的问题?

我认为将了解哪些对象实例化的症结放在温莎城堡上并不是最好的前进方式;您肯定需要访问一些容器方法,这样做会 link 您的组件到 Castle,这是不应该发生的。

我建议改为创建一个组件 IBouncer。该组件将作为单例注入所有 IFooConsumer 中,这将在创建和处置时调用它(处置是一种选择,您可以使用其他方法)

public interface IBouncer {
     IEnumerable<IFooConsumer> WhoIsInside {get;}
     void WelcomeTo(IFooConsumer consumer);
     void EscortOut(IFooConsumer consumer);
}

public Consumer: IFooConsumer {
    public Consumer(IBouncer bouncer) {
        bouncer.WelcomeTo(this);
    }

    public Dispose() {
        bouncer.EscortOut(this); // dispose pattern ommitted
    }
}

现在不用将 IFooConsumer 的列表传递给您的 Bar,只需向其中添加 IBouncer 并询问其中有哪些消费者。

class Bar
{
    public Bar(IBouncer bouncer) { ... }

    public void Foo()
    {
        // foo-ing
        foreach (var f in bouncer.WhoIsInside) f.FooHappened();
    }
}

您可以创建一个如下所示的简单工具,它会在每次实例化组件时进行事件注册。下面的代码用于将 Winsor 与 Caliburn.Micro 一起使用。这也将确保事件被注销,否则会导致奇怪的行为。在您的情况下,我不会让 Bar 直接将事件触发到所有 classes,而是使用单例组件(如下面的 IEventAggregator)将事件触发到多个 classes。这也将确保事件被注销,否则会导致奇怪的行为。在代码中,每个派生自 IHandle 的 class 都将接收事件。您可以根据自己的需要进行更改。

如果您有任何问题,请告诉我。

class EventRegistrationFacility : AbstractFacility
{
    private IEventAggregator _eventAggregator;
    protected override void Init()
    {
        Kernel.ComponentCreated += ComponentCreated;
        Kernel.ComponentDestroyed += ComponentDestroyed;
    }

    void ComponentCreated(Castle.Core.ComponentModel model, object instance)
    {
        if (!(instance is IHandle)) return;
        if (_eventAggregator == null) _eventAggregator = Kernel.Resolve<IEventAggregator>();
        _eventAggregator.Subscribe(instance);
    }

    void ComponentDestroyed(Castle.Core.ComponentModel model, object instance)
    {
        if (!(instance is IHandle)) return;
        if (_eventAggregator == null) return;
        _eventAggregator.Unsubscribe(instance);
    }

}

===编辑====

如 Sammy 所述,将其与保镖相结合:

public interface IBouncer {
    IEnumerable<IFooConsumer> WhoIsInside {get;}
    void WelcomeTo(IFooConsumer consumer);
    void EscortOut(IFooConsumer consumer);
}

public class Bouncer {
    private IList<IFooConsumer> _inside {get;}
    void WelcomeTo(IFooConsumer consumer) {
        _inside.Add(consumer);
}
    void EscortOut(IFooConsumer consumer);
        _inside.Remove(consumer);
    }
    IEnumerable<IFooConsumer> WhoIsInside {
        get {
            return _inside;
        }
    }



public Consumer: IFooConsumer {
    FooHappened() {
        // Do something.
}
    // no need to implement constructor/dispose
}


class Bar
{
    public Bar(IBouncer bouncer) { ... }

    public void Foo()
    {
        // foo-ing ==> alernatively create a function on Bouncer that does this. And keep WhoIsInside private.
        foreach (var f in bouncer.WhoIsInside) f.FooHappened();
    }
}


class BouncerRegistrationFacility : AbstractFacility
{
    private IBouncer _bouncer
    protected override void Init()
    {
        Kernel.ComponentCreated += ComponentCreated;
        Kernel.ComponentDestroyed += ComponentDestroyed;
    }

    void ComponentCreated(Castle.Core.ComponentModel model, object instance)
    {
        if (!(instance is IFooConsumer)) return;
        if (_bouncer == null) _bouncer = Kernel.Resolve<IEventAggregator>();
        _bouncer.WelcomeTo(instance);
    }

    void ComponentDestroyed(Castle.Core.ComponentModel model, object instance)
    {
        if (!(instance is IFooConsumer)) return;
        if (_bouncer == null) return;
        _bouncer.EscortOut(instance);
    }
}

尽管您需要更多代码来编写该工具,但 FooConsumers 无需 register/unregister 自己。由于注册码最初必须写在所有的 FooConsumers 中,所以它往往会重复。这样 subscription/unsubscription 就作为 commission/decommission 的要求完成了,只需要处理一次。

P.S。代码是用记事本编写的,可能包含编译错误。