使用Ninject进行惰性泛型委托初始化

时间:2010-02-25 13:52:23

标签: delegates lazy-loading generics ninject

我正在使用Ninject 1.0,并希望能够将惰性初始化委托注入构造函数。因此,给定通用委托定义:

public delegate T LazyGet<T>();

我只想将它绑定到IKernel.Get(),以便我可以将惰性getter传递给构造函数,例如。

public class Foo
{
    readonly LazyGet<Bar> getBar;

    public Foo( LazyGet<Bar> getBar )
    {
        this.getBar = getBar;
    }
}

但是,我不能简单地调用Bind<LazyGet<T>>(),因为它是一个开放的泛型类型。我需要这是一个开放的泛型,所以我不必将所有不同的懒惰绑定绑定到显式类型。在上面的示例中,应该可以动态创建一个调用IKernel.Get<T>()

的通用委托

如何使用Ninject 1.0实现这一目标?

3 个答案:

答案 0 :(得分:0)

不完全理解这个问题,但你能用反射吗?类似的东西:

// the type of T you want to use
Type bindType;
// the kernel you want to use
IKernel k;

// note - not compile tested
MethodInfo openGet = typeof(IKernel).GetMethod("Get`1");
MethodInfo constGet = openGet.MakeGenericMethod(bindType);

Type delegateType = typeof(LazyGet<>).MakeGenericType(bindType);
Delegate lazyGet = Delegate.CreateDelegate(delegateType, k, constGet);

使用lazyGet会让你做你想做的事吗?请注意,如果在编译上下文中不知道bindType,则可能还必须通过反射调用Foo类。

答案 1 :(得分:0)

我相当确定这样做的唯一方法(没有一些脏的反射代码)是将你的委托与类型params绑定。这意味着需要针对您使用的每种类型进行操作。您可以使用BindingGenerator批量执行此操作,但它可能会有点难看。

如果有更好的解决方案(一个干净的解决方案),我很乐意听到它,因为我不时会遇到这个问题。

答案 2 :(得分:0)

another similar question我回答:

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>());
    }
}