懒惰依赖注入懒惰

2023-09-03 07:05:47 作者:一只哀伤的猫

我所在的Ninject作为IoC容器的项目。我担心的是,很多类有这样那样的构造函数:

I have a project where the Ninject is used as IoC container. My concern is that a lot of classes have such kind of constructors:

[Inject]
public HomeController(UserManager userManager, RoleManager roleManager, BlahblahManager blahblahManager) {
   _userManager = userManager;
   _roleManager = roleManager;
   _blahblahManager = blahblahManager;
}

如果我不希望有这些类的所有实例一次?

What if I don't want to have all instances of these classes at once?

这样的,当这一切类包裹延迟< T> ,并传递给构造不正是我需要的。尚未创建 T 实例,但延迟< T> 的实例已存储在内存中

The way, when all this classes are wrapped by Lazy<T> and passed to constructor is not exactly what I need. The T instances are not created yet, but Lazy<T> instances are already stored in memory.

我的同事是在暗示我使用工厂模式来有超过所有实例的控制,但我不知道国际奥委会有这样伟大的设计错误。

My colleague is suggesting me to use Factory pattern to have control over all instantiations, but I'm not sure that IoC have such great design bug.

有变通方法对于这种情况,或国际奥委会真的有这么大的缺陷,在它的设计?也许我应该用另一种IoC容器?

Is there a workaround for this situation or IoC really have such big defect in it's design? Maybe I should use another IoC container?

有什么建议?

推荐答案

在我看来,你正在做 premature优化:不这样做,

Seems to me that you are doing premature optimization: don't do it.

你的服务的构造应该做的无非就是存储,它需要在私人领域的依赖。在这种情况下,建立这样的对象真是重量轻。不要忘了在.NET中的对象创建是非常快。在大多数情况下,从性能的角度来看,它只是无所谓的依赖关系是否得到注射与否。尤其是比较对象数量的应用程序(和你使用的框架)的其余部分时吐出。真正的成本是当你开始使用Web服务,数据库或文件系统,因为它们会引起更大的延迟。

The constructors of your services should do nothing more than storing the dependencies that it takes in private fields. In that case the creation of such an object is really light weight. Don't forget that object creation in .NET is really fast. In most cases, from a performance perspective, it just doesn't matter whether those dependencies get injected or not. Especially when comparing to the amount of objects the rest of your application (and the frameworks you use) are spitting out. The real costs is when you start using web services, databases or the file system, because they cause a much bigger delay.

如果创作真的很贵,你通常应该躲在一个代理,而不是注入延迟&LT的创作; T&GT; ,因为这可以让应用程序能够无视事实上,有一个延迟的创建(包括应用程序code和测试code正变得越来越复杂,当你这样做)的机制。然而,延迟&LT; T&GT; 只占用20个字节的内存(假设一个32位进程),并创建一个延迟&LT的; T&GT; 实例几乎是免费的。所以没有必要担心这一点,当你在与紧实的内存限制的环境中的除外。

If the creation is really expensive, you should normally hide the creation behind a proxy instead of injecting a Lazy<T>, since this allows the application to be oblivious to the fact that there is a mechanism to delay the creation (both your application code and test code are becoming more complex when you do this). However, a Lazy<T> just consumes 20 bytes of memory (assuming a 32bit process) and the creation of an Lazy<T> instance is practically free. So there is no need to worry about this, except when you’re in an environment with really tight memory constraints.

如果内存消耗问题,请尝试用一辈子是大于短暂的注册服务。你可以做一个每个请求,每个web请求,或单。我甚至可以说,当你在一个环境中创建新的对象是一个问题,你应该只使用单服务,(但这是不可能的,你的工作在这样的环境)。

And if memory consumption is a problem, try registering services with a lifetime that is bigger than transient. You could do a per request, per web request, or singleton. I would even say that when you're in an environment where creating new objects is a problem, you should probably only use singleton services (but it's unlikely that you're working on such an environment).

请注意,Ninject为.NET较慢DI框架之一。如果这是困扰你,切换到速度更快的容器。一些容器具有性能接近newing了对象图的手。

Do note that Ninject is one of the slower DI frameworks for .NET. If that's troubling you, switch to a faster container. Some containers have performance that is near newing up object graphs by hand.

另外还要注意的是,使用延迟&LT; T&GT; 的依赖是一个漏抽象(这是违反依赖倒置原则的)。请阅读this回答了解更多信息。

Also note that the use of Lazy<T> as dependency is a leaky abstraction (which is a violation of the Dependency Inversion Principle). Please read this answer for more information.