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

Posted

技术标签:

【中文标题】使用 Ninject 进行惰性泛型委托初始化【英文标题】:Lazy generic delegate initialisation using Ninject 【发布时间】:2011-01-21 00:29:21 【问题描述】:

我正在使用 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&lt;LazyGet&lt;T&gt;&gt;(),因为它是一个开放的泛型类型。我需要这是一个开放的泛型,这样我就不必将所有不同的惰性获取绑定到显式类型。在上面的示例中,应该可以动态创建调用IKernel.Get&lt;T&gt;() 的通用委托。

如何使用 Ninject 1.0 实现这一点?

【问题讨论】:

注入一个显式惰性的依赖是,IMO,一个泄漏抽象。请参阅此处了解更多信息:blog.ploeh.dk/2010/01/20/… 我知道,但我正在转换一个现有的代码库,它有很多高度耦合的静态。这只是摆脱所有静态类的中间第一步。 很公平 :) 无论如何,我从来没有想过我的评论不屑一顾。但是,我指出的帖子确实通过将惰性实现为装饰器提供了一条出路。我只是不想将其作为答案提供,因为您可能会从其他人那里得到正确的 Ninject 答案:) 我不是 100% 清楚你的用例。但是您可以通过语法 Bind(typeof(LazyGet)) 绑定开放的泛型类型。不确定您要尝试将开放的通用委托绑定到什么。 您可以在我的书中找到有关此内容的更多信息以及其他更多信息:affiliate.manning.com/idevaffiliate.php?id=1150_236 【参考方案1】:

来自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>());
    

【讨论】:

【参考方案2】:

我相当肯定,做到这一点的唯一方法(没有一些肮脏的反射代码)是将您的委托与类型参数绑定。这意味着需要为您使用的每种单独类型完成此操作。您可以使用 BindingGenerator 批量执行此操作,但它可能会有点难看。

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

【讨论】:

【参考方案3】:

不完全理解这个问题,但你可以使用反射吗?比如:

// 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 类。

【讨论】:

感谢您的代码,但它是“赤裸裸的”——您没有展示它是如何在 Ninject 中注册的。我可以像你一样轻松地编写代码,但是我如何告诉 Ninject 绑定它,以便当它创建一个接受惰性委托的类型的实例时,它将它绑定到它自己的 Get 方法?我在做什么似乎很清楚:我想将参数绑定到 Ninject 自己的 Get 方法,以便当对象请求该类型的实例时,它会调用 Ninject 的 Get。

以上是关于使用 Ninject 进行惰性泛型委托初始化的主要内容,如果未能解决你的问题,请参考以下文章

C#规范整理·泛型委托事件

Kotlin小知识之泛型和委托

C#规范整理·泛型委托事件

在 SwiftUI 中创建惰性 NavigationLink 时出现泛型问题

泛型委托使用

C#泛型类,泛型接口,泛型方法,泛型委托怎么用