代码之家  ›  专栏  ›  技术社区  ›  devlife

用Ninject延迟加载

  •  13
  • devlife  · 技术社区  · 16 年前

    我正在评估ninject2,但除了通过内核之外,似乎还不知道如何进行延迟加载。

    从我所看到的情况来看,这样做违背了使用[Inject]属性的目的。 是否可以使用InjectAttribute但得到延迟加载?我不想每次实例化一个对象时都强制完成对象图的构造。

    2 回复  |  直到 16 年前
        1
  •  19
  •   Aaronaught    12 年前

    更新: Lazy<T> ),而另一个答案,虽然略为更新,但现在仍然有点过时。我将在下面留下我的原始答案,以防有人被旧版本卡住,但不建议将其用于最新版本的Ninject或.NET。

    第九个对象 Factory Extension 是现代的方法。它将自动连接任何参数或属性。您不需要单独的绑定—只需按常规方式设置服务,其余的由扩展处理。

    Func<T> 论据。它们的不同之处在于每次都会创建一个新实例,所以它实际上是一个工厂,而不仅仅是懒惰的实例化。只是指出这一点,因为文档并不完全清楚。


    这实际上并不是Ninject本身的限制—如果您仔细考虑一下,就不可能有一个“延迟依赖”,除非(a)被注入的依赖本身就是一个延迟加载程序,比如 Lazy<T> 类,或者(b)所有依赖项的属性和方法都使用延迟实例化。 什么

    你可以通过使用 提供程序接口 方法绑定 并绑定一个开放泛型类型。假设您没有.NET 4,则必须自己创建接口和实现:

    public interface ILazy<T>
    {
        T Value { get; }
    }
    
    public class LazyLoader<T> : ILazy<T>
    {
        private bool isLoaded = false;
        private T instance;
        private Func<T> loader;
    
        public LazyLoader(Func<T> loader)
        {
            if (loader == null)
                throw new ArgumentNullException("loader");
            this.loader = loader;
        }
    
        public T Value
        {
            get
            {
                if (!isLoaded)
                {
                    instance = loader();
                    isLoaded = true;
                }
                return instance;
            }
        }
    }
    

    Bind<ISomeService>().To<SomeService>();
    Bind<IOtherService>().To<OtherService>();
    

    Bind(typeof(ILazy<>)).ToMethod(ctx =>
    {
        var targetType = typeof(LazyLoader<>).MakeGenericType(ctx.GenericArguments);
        return ctx.Kernel.Get(targetType);
    });
    

    之后,可以引入延迟依赖参数/属性:

    public class MyClass
    {
        [Inject]
        public MyClass(ILazy<ISomeService> lazyService) { ... }
    }
    

    整个的 操作lazy-Ninject仍然需要实际创建 LazyLoader ,但任何 的依赖关系 ISomeService 直到 MyClass 检查 Value 那是什么 lazyService .

    明显的缺点是 ILazy<T> 不执行 T 类名 任何


    据我所知,不用编写堆积如山的代码的唯一方法是使用代理生成器,如 Castle DynamicProxy ,或使用 Ninject Interception Extension . 这将是相当复杂的,我不认为你会想走这条路线,除非你必须。

        2
  •  17
  •   Ed Chapel    13 年前

    有一种更简单的方法:

    public class Module : NinjectModule
    {
        public override void Load()
        {
            Bind(typeof(Lazy<>)).ToMethod(ctx => 
                    GetType()
                        .GetMethod("GetLazyProvider", BindingFlags.Instance | BindingFlags.NonPublic)
                        .MakeGenericMethod(ctx.GenericArguments[0])
                        .Invoke(this, new object[] { ctx.Kernel }));
        }
    
        protected Lazy<T> GetLazyProvider<T>(IKernel kernel)
        {
            return new Lazy<T>(() => kernel.Get<T>());
        }
    }
    
    推荐文章