来利鸡 發表於 2025-6-26 08:48:48

全面解析.NET中的依赖注入(DI)

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">一、依赖注入核心原理</a></li><ul class="second_class_ul"><li><a href="#_lab2_0_0">1. 控制反转(IoC)与DI关系</a></li><li><a href="#_lab2_0_1">2. .NET DI核心组件</a></li></ul><li><a href="#_label1">二、服务生命周期</a></li><ul class="second_class_ul"></ul><li><a href="#_label2">三、DI容器实现原理</a></li><ul class="second_class_ul"><li><a href="#_lab2_2_2">1. 服务注册流程</a></li><li><a href="#_lab2_2_3">2. 服务解析流程</a></li></ul><li><a href="#_label3">四、高级实现方法</a></li><ul class="second_class_ul"><li><a href="#_lab2_3_4">1. 工厂模式注册</a></li><li><a href="#_lab2_3_5">2. 泛型服务注册</a></li><li><a href="#_lab2_3_6">3. 多实现解决方案</a></li></ul><li><a href="#_label4">五、ASP.NET Core中的DI集成</a></li><ul class="second_class_ul"><li><a href="#_lab2_4_7">1. 控制器注入</a></li><li><a href="#_lab2_4_8">2. 视图注入</a></li><li><a href="#_lab2_4_9">3. 中间件注入</a></li></ul><li><a href="#_label5">六、自定义DI容器实现</a></li><ul class="second_class_ul"><li><a href="#_lab2_5_10">1. 简易DI容器实现</a></li><li><a href="#_lab2_5_11">2. 属性注入实现</a></li></ul><li><a href="#_label6">七、最佳实践</a></li><ul class="second_class_ul"><li><a href="#_lab2_6_12">1. 服务设计原则</a></li><li><a href="#_lab2_6_13">2. 常见陷阱</a></li></ul><li><a href="#_label7">八、性能优化</a></li><ul class="second_class_ul"><li><a href="#_lab2_7_14">1. 避免过度注入</a></li><li><a href="#_lab2_7_15">2. 编译时注入</a></li></ul></ul></div><p class="maodian"><a name="_label0"></a></p><h2>一、依赖注入核心原理</h2>
<p class="maodian"><a name="_lab2_0_0"></a></p><h3>1. 控制反转(IoC)与DI关系</h3>
<ul><li><strong>控制反转(IoC)</strong>:框架控制程序流程,而非开发者</li><li><strong>依赖注入(DI)</strong>:IoC的一种实现方式,通过外部提供依赖对象</li></ul>
<p class="maodian"><a name="_lab2_0_1"></a></p><h3>2. .NET DI核心组件</h3>
<ul><li><code>IServiceCollection</code>:服务注册容器</li><li><code>IServiceProvider</code>:服务解析器</li><li><code>ServiceDescriptor</code>:服务描述符(包含生命周期信息)</li></ul>
<p class="maodian"><a name="_label1"></a></p><h2>二、服务生命周期</h2>
<p><strong>三种生命周期类型</strong></p>
<table><thead><tr><th>生命周期</th><th>描述</th><th>适用场景</th></tr></thead><tbody><tr><td>Transient</td><td>每次请求创建新实例</td><td>轻量级、无状态服务</td></tr><tr><td>Scoped</td><td>同一作用域内共享实例</td><td>Web请求上下文</td></tr><tr><td>Singleton</td><td>全局单例</td><td>配置服务、缓存</td></tr></tbody></table>
<div class="jb51code"><pre class="brush:csharp;">// 注册示例
services.AddTransient&lt;ITransientService, TransientService&gt;();
services.AddScoped&lt;IScopedService, ScopedService&gt;();
services.AddSingleton&lt;ISingletonService, SingletonService&gt;();
</pre></div>
<p class="maodian"><a name="_label2"></a></p><h2>三、DI容器实现原理</h2>
<p class="maodian"><a name="_lab2_2_2"></a></p><h3>1. 服务注册流程</h3>
<div class="jb51code"><pre class="brush:csharp;">public static IServiceCollection AddTransient&lt;TService, TImplementation&gt;(this IServiceCollection services)
{
    // 创建服务描述符
    var descriptor = new ServiceDescriptor(
      typeof(TService),
      typeof(TImplementation),
      ServiceLifetime.Transient);
   
    // 添加到集合
    services.Add(descriptor);
    return services;
}
</pre></div>
<p class="maodian"><a name="_lab2_2_3"></a></p><h3>2. 服务解析流程</h3>
<div class="jb51code"><pre class="brush:csharp;">public object GetService(Type serviceType)
{
    // 1. 查找服务描述符
    var descriptor = _descriptors.FirstOrDefault(d =&gt; d.ServiceType == serviceType);
   
    // 2. 根据生命周期创建实例
    if (descriptor.Lifetime == ServiceLifetime.Singleton)
    {
      if (_singletons.TryGetValue(serviceType, out var instance))
            return instance;
      
      instance = CreateInstance(descriptor);
      _singletons = instance;
      return instance;
    }
    // ...处理Scoped和Transient
}
</pre></div>
<p class="maodian"><a name="_label3"></a></p><h2>四、高级实现方法</h2>
<p class="maodian"><a name="_lab2_3_4"></a></p><h3>1. 工厂模式注册</h3>
<div class="jb51code"><pre class="brush:csharp;">services.AddTransient&lt;IService&gt;(provider =&gt; {
    var otherService = provider.GetRequiredService&lt;IOtherService&gt;();
    return new ServiceImpl(otherService, "参数");
});
</pre></div>
<p class="maodian"><a name="_lab2_3_5"></a></p><h3>2. 泛型服务注册</h3>
<div class="jb51code"><pre class="brush:csharp;">services.AddTransient(typeof(IRepository&lt;&gt;), typeof(Repository&lt;&gt;));
</pre></div>
<p class="maodian"><a name="_lab2_3_6"></a></p><h3>3. 多实现解决方案</h3>
<div class="jb51code"><pre class="brush:csharp;">// 注册多个实现
services.AddTransient&lt;IMessageService, EmailService&gt;();
services.AddTransient&lt;IMessageService, SmsService&gt;();

// 解析时获取所有实现
var services = provider.GetServices&lt;IMessageService&gt;();
</pre></div>
<p class="maodian"><a name="_label4"></a></p><h2>五、ASP.NET Core中的DI集成</h2>
<p class="maodian"><a name="_lab2_4_7"></a></p><h3>1. 控制器注入</h3>
<div class="jb51code"><pre class="brush:csharp;">public class HomeController : Controller
{
    private readonly ILogger _logger;
   
    public HomeController(ILogger&lt;HomeController&gt; logger)
    {
      _logger = logger; // 自动注入
    }
}
</pre></div>
<p class="maodian"><a name="_lab2_4_8"></a></p><h3>2. 视图注入</h3>
<div class="jb51code"><pre class="brush:csharp;">@inject IConfiguration Config
&lt;p&gt;当前环境: @Config["Environment"]&lt;/p&gt;
</pre></div>
<p class="maodian"><a name="_lab2_4_9"></a></p><h3>3. 中间件注入</h3>
<div class="jb51code"><pre class="brush:csharp;">public class CustomMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;
   
    public CustomMiddleware(
      RequestDelegate next,
      ILogger&lt;CustomMiddleware&gt; logger)
    {
      _next = next;
      _logger = logger;
    }
   
    public async Task InvokeAsync(HttpContext context)
    {
      // 使用注入的服务
      _logger.LogInformation("中间件执行");
      await _next(context);
    }
}
</pre></div>
<p class="maodian"><a name="_label5"></a></p><h2>六、自定义DI容器实现</h2>
<p class="maodian"><a name="_lab2_5_10"></a></p><h3>1. 简易DI容器实现</h3>
<div class="jb51code"><pre class="brush:csharp;">public class SimpleContainer : IServiceProvider
{
    private readonly Dictionary&lt;Type, ServiceDescriptor&gt; _descriptors;
   
    public SimpleContainer(IEnumerable&lt;ServiceDescriptor&gt; descriptors)
    {
      _descriptors = descriptors.ToDictionary(x =&gt; x.ServiceType);
    }
   
    public object GetService(Type serviceType)
    {
      if (!_descriptors.TryGetValue(serviceType, out var descriptor))
            return null;
            
      if (descriptor.ImplementationInstance != null)
            return descriptor.ImplementationInstance;
            
      var type = descriptor.ImplementationType ?? descriptor.ServiceType;
      return ActivatorUtilities.CreateInstance(this, type);
    }
}
</pre></div>
<p class="maodian"><a name="_lab2_5_11"></a></p><h3>2. 属性注入实现</h3>
<div class="jb51code"><pre class="brush:csharp;">public static class PropertyInjectionExtensions
{
    public static void AddPropertyInjection(this IServiceCollection services)
    {
      services.AddTransient&lt;IStartupFilter, PropertyInjectionStartupFilter&gt;();
    }
}

public class PropertyInjectionStartupFilter : IStartupFilter
{
    public Action&lt;IApplicationBuilder&gt; Configure(Action&lt;IApplicationBuilder&gt; next)
    {
      return builder =&gt;
      {
            builder.Use(async (context, nextMiddleware) =&gt;
            {
                var endpoint = context.GetEndpoint();
                if (endpoint?.Metadata.GetMetadata&lt;ControllerActionDescriptor&gt;() is { } descriptor)
                {
                  var controller = context.RequestServices.GetRequiredService(descriptor.ControllerTypeInfo);
                  // 反射实现属性注入
                  InjectProperties(controller, context.RequestServices);
                }
                await nextMiddleware();
            });
            next(builder);
      };
    }
   
    private void InjectProperties(object target, IServiceProvider services)
    {
      var properties = target.GetType().GetProperties()
            .Where(p =&gt; p.CanWrite &amp;&amp; p.GetCustomAttribute&lt;InjectAttribute&gt;() != null);
            
      foreach (var prop in properties)
      {
            var service = services.GetService(prop.PropertyType);
            if (service != null)
                prop.SetValue(target, service);
      }
    }
}
</pre></div>
<p class="maodian"><a name="_label6"></a></p><h2>七、最佳实践</h2>
<p class="maodian"><a name="_lab2_6_12"></a></p><h3>1. 服务设计原则</h3>
<ul><li>遵循显式依赖原则</li><li>避免服务定位 器模式(反模式)</li><li>保持服务轻量级</li></ul>
<p class="maodian"><a name="_lab2_6_13"></a></p><h3>2. 常见陷阱</h3>
<div class="jb51code"><pre class="brush:csharp;">// 错误示例:捕获Scoped服务到Singleton中
services.AddSingleton&lt;IBackgroundService&gt;(provider =&gt; {
    var scopedService = provider.GetRequiredService&lt;IScopedService&gt;(); // 危险!
    return new BackgroundService(scopedService);
});

// 正确做法:使用IServiceScopeFactory
services.AddSingleton&lt;IBackgroundService&gt;(provider =&gt; {
    var scopeFactory = provider.GetRequiredService&lt;IServiceScopeFactory&gt;();
    return new BackgroundService(scopeFactory);
});
</pre></div>
<p class="maodian"><a name="_label7"></a></p><h2>八、性能优化</h2>
<p class="maodian"><a name="_lab2_7_14"></a></p><h3>1. 避免过度注入</h3>
<div class="jb51code"><pre class="brush:csharp;">// 不好:注入过多服务
public class OrderService(
    ILogger logger,
    IEmailService emailService,
    ISmsService smsService,
    IRepository repo,
    ICache cache,
    IConfig config)
{
    // ...
}

// 改进:使用聚合服务
public class OrderService(
    ILogger logger,
    INotificationService notification,
    IOrderInfrastructure infra)
{
    // ...
}
</pre></div>
<p class="maodian"><a name="_lab2_7_15"></a></p><h3>2. 编译时注入</h3>
<div class="jb51code"><pre class="brush:csharp;">
public class MyService : IMyService
{
    // ...
}

// 使用Source Generator自动生成注册代码
static partial class ServiceRegistration
{
    static partial void AddGeneratedServices(IServiceCollection services)
    {
      services.AddTransient&lt;IMyService, MyService&gt;();
    }
}
</pre></div>
<p>.NET的依赖注入系统是框架的核心基础设施,理解其原理和实现方式有助于编写更可测试、更松耦合的应用程序。</p>
頁: [1]
查看完整版本: 全面解析.NET中的依赖注入(DI)