You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在并非所有依赖项都始终被使用时应用依赖注入?

Understanding Conditional Dependencies in Dependency Injection

Great question—this is exactly the kind of scenario where DI's flexibility really shines once you know the right patterns to use. You don't have to pre-instantiate class C (the mailer) for every request, even if you're following DI principles. Here's how to handle it:

The Core Idea: Inject a "Creator" Instead of the Instance

DI is all about inverting control—but control doesn't mean you have to create every dependency upfront. When a dependency is only needed under specific conditions, you can inject a factory, provider, or lazy initializer instead of the concrete instance itself. This lets you defer the creation of class C until it's actually required.

Example Implementation

Let's walk through what this might look like in code:

  1. First, define an interface for your mailer to keep things decoupled:
public interface IMailer
{
    void SendEmail(string recipient, string message);
}

public class Mailer : IMailer
{
    // Mailer implementation (e.g., SMTP setup, template rendering)
}
  1. Create a factory that knows how to create an IMailer instance:
public interface IMailerFactory
{
    IMailer CreateMailer();
}

public class MailerFactory : IMailerFactory
{
    public IMailer CreateMailer()
    {
        // You can add any setup logic here (config loading, dependency setup)
        return new Mailer();
    }
}
  1. Inject the factory into class B (the listener) instead of IMailer:
public class Listener
{
    private readonly IMailerFactory _mailerFactory;

    // Inject the factory, not the mailer itself
    public Listener(IMailerFactory mailerFactory)
    {
        _mailerFactory = mailerFactory;
    }

    public void HandleEvent(bool triggerEmail)
    {
        if (triggerEmail)
        {
            // Only create the mailer when we need it
            var mailer = _mailerFactory.CreateMailer();
            mailer.SendEmail("user@example.com", "Your event was triggered!");
        }
        // No mailer is created if the condition isn't met
    }
}
  1. Wire this up in your DI container (e.g., ASP.NET Core):
services.AddScoped<IMailerFactory, MailerFactory>();
services.AddScoped<Listener>();
services.AddScoped<ControllerA>();

Why This Works

  • You maintain full decoupling: Class B doesn't know the concrete implementation of IMailer—it only relies on the factory interface.
  • No wasted resources: Class C is only instantiated when the specific condition is met, avoiding unnecessary object creation for requests that don't need it.
  • You retain control: Your DI container manages the factory, so you can still define how IMailer instances are created (scoped, singleton, etc.) without hardcoding that logic in class B.

Other Options to Consider

  • Lazy: If you're using a .NET DI container, you can inject Lazy<IMailer> directly. This delays instantiation until you access the Value property, cutting down on boilerplate compared to a full factory.
  • Service Locator (use cautiously): Some containers let you resolve dependencies on-demand, but this is often considered an anti-pattern because it hides a class's true dependencies. Factories are generally a cleaner, more maintainable approach.

The key takeaway is that DI isn't about injecting every possible dependency upfront—it's about letting external code control how and when dependencies are created. For conditional dependencies, delegating creation to a factory or lazy initializer aligns perfectly with DI principles while keeping your code efficient.

内容的提问来源于stack exchange,提问作者Hans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:41:12