调整 Unity 依赖注入以使用 Lazy<T> / Func<T>

Adjust Unity Dependency injection to use Lazy<T> / Func<T>

我正在开发一个使用 Unity 依赖注入的项目,但加载性能正在慢慢变差。我正在尝试调整代码以利用 Lazy<T>(或 Func<T>),因此我正在尝试找到一种方法来使用 Lazy<T>(或 Func<T>) 或者有某种可以调整注册类型或构造函数的工厂,但我似乎无法找到一种可能的方法来做到这一点

目前我有很多服务类喜欢

public Service1(IClassLogic<GetReq, GetRes> getClass, IClassLogic<AddReq, AddRes> addClass, IClassLogic<UpdateReq, UpdateRes> updateClass, IClassLogic<DeleteReq, DeleteRes> deleteClass....){...}

那么我的注册类似于

container.RegisterType<IClassLogic<GetReq, GetRes>, GetClass>();
container.RegisterType<IClassLogic<AddReq, AddRes>, AddClass>();
container.RegisterType<IClassLogic<UpdateReq, UpdateRes>, UpdateClass>();
container.RegisterType<IClassLogic<DeleteReq, DeleteRes>, DeleteClass>();
...

理想情况下,我不想将所有签名更改为

public Service1(Lazy<IClassLogic<GetReq, GetRes>> getClass, Lazy<IClassLogic<AddReq, AddRes>> addClass...

任何指点将不胜感激

首先给出一些关于 DI 的一般提示:

  • 你是对的,你不想改变构造函数的签名。您是 IoC 容器(在您的情况下为 Unity)应该使您能够根据需要设计界面和消费者。否则不是一个好的容器。
  • 当开始尝试使用 DI(和容器)时,我建议您自己将其连接起来。这让您深入了解它的工作原理并提供灵活性。 Mark Seemann 写了很多关于这方面的文章。
  • 您的服务的依赖项似乎非常拥挤。您不能通过组合一些(可能是 Facade)来重构以减少依赖性吗?
  • 使接口具体(而不是通用)使事情变得简单得多。仿制药有时弊大于利。

我编写了一个可以编译的快速示例(我还没有测试过)。我使用了与您的示例一致的通用接口,但使用了一些伪造的实现和字符串类型作为通用参数(未使用):

如果这是一个接口的实现:

public class ClassLogic : IClassLogic<string, string>
{
    public void Do()
    {
        // do stuff
    }
}

然后你可以像这样实现一个只在需要时(通过给定的 Func)创建实现的提供者:

public class ClassLogicProvider : IClassLogic<string, string>
{
private readonly Func<IClassLogic<string, string>> innerLogicFactory;

    public ClassLogicProvider(Func<IClassLogic<string, string>> innerLogicFactory)
    {
        this.innerLogicFactory = innerLogicFactory;
    }

    public void Do()
    {
        var classLogic = this.innerLogicFactory();
        classLogic.Do();
    }
}

然后像这样连接起来:

var container = new UnityContainer();
Func<IClassLogic<string, string>> classLogicFunc = () =>
        {
            // Create implementation on demand
            return new ClassLogic();
        };
container.RegisterType<IClassLogic<string, string>>(
            new InjectionFactory(c => {
                return new ClassLogicProvider(classLogicFunc);
            })
        );

这应该会在需要实施时为您提供所需的延迟创建。

防止使用 Func<T>Lazy<T> 作为依赖项以防止缓慢的对象图初始化。这些是有漏洞的抽象,因为它们将实现细节泄露给了消费者。这里的实现细节是创建此类服务的成本很高。

创建依赖项花费太多时间这一事实表明您的注入构造函数做了太多事情,而它们应该是 simple, fast and reliable

另一个明显的问题是您的组件违反了单一职责原则。构造函数中的依赖项超过 5 个是代码异味,也是违反单一职责原则的迹象。当您需要解析非常大的对象图时,某些容器会变慢,但是当您使组件变小且集中时,这个问题很可能会消失,因为要构建的对象图会小得多。