检查是否曾经创建过惰性单例

Check if a lazy singleton was ever created

使用 ninject,我有这样的绑定:

kernel.Bind<IFoo>().To<MyFoo>().InSingletonScope()
    .WithConstructorArgument("bar", new Action<IFoo>(foo =>
    {
        // some function here
    }));

我想做的是确定 IFoo 是否在没有实际尝试使用它的情况下构建(因为这会导致它被构建)。有简单的方法吗?

构建时触发一个布尔值,您可以检查 true/false 并获取该值

一般

这似乎是题外话,但您可能会发现几个有用的单例实现,作者 Jon Skeet here

问题

如果我理解正确的话,您只需添加一个 bool 属性 来指示实例是否已创建。例如:

public static bool IsCreated { get { return _instance != null; } }

不管怎么用,都应该节省线程..

实现包装器

public static class FooWrapper 
{
    public static bool IsCreated { get; private set; } // default false

    public static IFoo GetInstance()
    {
        IsCreated = true;

        // return the Singleton Instance of IFoo
    }
}

确保访问您的 IFoo 实例的唯一方法是使用 FooWrapper.GetInstance()

如果您充分了解 Ninject 的内部结构,您可能会找到一种方法来查找仅在调用此绑定后才会存在的对象的存在。但是,仅将绑定设置为设置可检查标志的工厂方法会更容易。

kernel.Bind<IFoo>().ToMethod(
    kernel => {
        Tracker.FooIsInitialized = true;
        return new MyFoo(kernel.Get<IDependency>());
    })
    .InSingletonScope()
    .WithConstructorArgument("bar", new Action<IFoo>(foo =>
    {
        // some function here
    }));

我认为这是应用正确模式的问题,例如代理模式:

public class LazyFooProxy : IFoo
{
    private readonly Lazy<IFoo> foo;
    public LazyFooProxy(Lazy<IFoo> foo) {
        this.foo = foo;
    }

    public bool IsCreated {
        get { return this.foo.IsValueCreated; }
    }

    void IFoo.Method() {
        this.foo.Value.Method();
    }
}

这里我们创建了一个 LazyFooProxy 代理 class 它能够延迟 IFoo 的创建并且它还允许检查 foo 是否已经创建(通过调用 Lazy<T>.IsValueCreated 属性).

现在您可以进行以下注册:

var lazyFoo = new LazyFooProxy(new Lazy<IFoo>(kernel.Get<MyFoo>));
kernel.Bind<IFoo>().ToInstance(lazyFoo);
kernel.Bind<MyFoo>().InSingletonScope();

现在您可以使用 LazyFooProxy.IsCreated 属性 检查是否创建了 MyFoo

您可以将 OnActivation(...) - 它以 Action 作为参数 - 添加到绑定中。有了这个你可以做任何你想做的事,包括将标志设置为真。

例如:

static bool fooWasCreated = false;

kernel.Bind<IFoo>().To<MyFoo>()
      .InSingletonScope()
      .OnActivation(fooInstance => fooWasCreated = true);

还有一个重载可用,您可以在其中访问 IContext。也没有必要使用静态变量,作为替代方案,您还可以访问另一个绑定的组件 InSingletonScope()