.NET 依賴注入(DI)全面解析

在這里插入圖片描述

文章目錄

    • 一、依賴注入核心原理
      • 1. 控制反轉(IoC)與DI關系
      • 2. .NET DI核心組件
    • 二、服務生命周期
      • 1. 三種生命周期類型
    • 三、DI容器實現原理
      • 1. 服務注冊流程
      • 2. 服務解析流程
    • 四、高級實現方法
      • 1. 工廠模式注冊
      • 2. 泛型服務注冊
      • 3. 多實現解決方案
    • 五、ASP.NET Core中的DI集成
      • 1. 控制器注入
      • 2. 視圖注入
      • 3. 中間件注入
    • 六、自定義DI容器實現
      • 1. 簡易DI容器實現
      • 2. 屬性注入實現
    • 七、最佳實踐
      • 1. 服務設計原則
      • 2. 常見陷阱
    • 八、性能優化
      • 1. 避免過度注入
      • 2. 編譯時注入

在這里插入圖片描述

一、依賴注入核心原理

1. 控制反轉(IoC)與DI關系

  • 控制反轉(IoC):框架控制程序流程,而非開發者
  • 依賴注入(DI):IoC的一種實現方式,通過外部提供依賴對象

2. .NET DI核心組件

  • IServiceCollection:服務注冊容器
  • IServiceProvider:服務解析器
  • ServiceDescriptor:服務描述符(包含生命周期信息)

二、服務生命周期

1. 三種生命周期類型

生命周期描述適用場景
Transient每次請求創建新實例輕量級、無狀態服務
Scoped同一作用域內共享實例Web請求上下文
Singleton全局單例配置服務、緩存
// 注冊示例
services.AddTransient<ITransientService, TransientService>();
services.AddScoped<IScopedService, ScopedService>();
services.AddSingleton<ISingletonService, SingletonService>();

三、DI容器實現原理

1. 服務注冊流程

public static IServiceCollection AddTransient<TService, TImplementation>(this IServiceCollection services)
{// 創建服務描述符var descriptor = new ServiceDescriptor(typeof(TService),typeof(TImplementation),ServiceLifetime.Transient);// 添加到集合services.Add(descriptor);return services;
}

2. 服務解析流程

public object GetService(Type serviceType)
{// 1. 查找服務描述符var descriptor = _descriptors.FirstOrDefault(d => d.ServiceType == serviceType);// 2. 根據生命周期創建實例if (descriptor.Lifetime == ServiceLifetime.Singleton){if (_singletons.TryGetValue(serviceType, out var instance))return instance;instance = CreateInstance(descriptor);_singletons[serviceType] = instance;return instance;}// ...處理Scoped和Transient
}

四、高級實現方法

1. 工廠模式注冊

services.AddTransient<IService>(provider => {var otherService = provider.GetRequiredService<IOtherService>();return new ServiceImpl(otherService, "參數");
});

2. 泛型服務注冊

services.AddTransient(typeof(IRepository<>), typeof(Repository<>));

3. 多實現解決方案

// 注冊多個實現
services.AddTransient<IMessageService, EmailService>();
services.AddTransient<IMessageService, SmsService>();// 解析時獲取所有實現
var services = provider.GetServices<IMessageService>();

五、ASP.NET Core中的DI集成

1. 控制器注入

public class HomeController : Controller
{private readonly ILogger _logger;public HomeController(ILogger<HomeController> logger){_logger = logger; // 自動注入}
}

2. 視圖注入

@inject IConfiguration Config
<p>當前環境: @Config["Environment"]</p>

3. 中間件注入

public class CustomMiddleware
{private readonly RequestDelegate _next;private readonly ILogger _logger;public CustomMiddleware(RequestDelegate next,ILogger<CustomMiddleware> logger){_next = next;_logger = logger;}public async Task InvokeAsync(HttpContext context){// 使用注入的服務_logger.LogInformation("中間件執行");await _next(context);}
}

六、自定義DI容器實現

1. 簡易DI容器實現

public class SimpleContainer : IServiceProvider
{private readonly Dictionary<Type, ServiceDescriptor> _descriptors;public SimpleContainer(IEnumerable<ServiceDescriptor> descriptors){_descriptors = descriptors.ToDictionary(x => 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);}
}

2. 屬性注入實現

public static class PropertyInjectionExtensions
{public static void AddPropertyInjection(this IServiceCollection services){services.AddTransient<IStartupFilter, PropertyInjectionStartupFilter>();}
}public class PropertyInjectionStartupFilter : IStartupFilter
{public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next){return builder =>{builder.Use(async (context, nextMiddleware) =>{var endpoint = context.GetEndpoint();if (endpoint?.Metadata.GetMetadata<ControllerActionDescriptor>() 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 => p.CanWrite && p.GetCustomAttribute<InjectAttribute>() != null);foreach (var prop in properties){var service = services.GetService(prop.PropertyType);if (service != null)prop.SetValue(target, service);}}
}

七、最佳實踐

1. 服務設計原則

  • 遵循顯式依賴原則
  • 避免服務定位器模式(反模式)
  • 保持服務輕量級

2. 常見陷阱

// 錯誤示例:捕獲Scoped服務到Singleton中
services.AddSingleton<IBackgroundService>(provider => {var scopedService = provider.GetRequiredService<IScopedService>(); // 危險!return new BackgroundService(scopedService);
});// 正確做法:使用IServiceScopeFactory
services.AddSingleton<IBackgroundService>(provider => {var scopeFactory = provider.GetRequiredService<IServiceScopeFactory>();return new BackgroundService(scopeFactory);
});

八、性能優化

1. 避免過度注入

// 不好:注入過多服務
public class OrderService(ILogger logger,IEmailService emailService,ISmsService smsService,IRepository repo,ICache cache,IConfig config)
{// ...
}// 改進:使用聚合服務
public class OrderService(ILogger logger,INotificationService notification,IOrderInfrastructure infra)
{// ...
}

2. 編譯時注入

[RegisterTransient(typeof(IMyService))]
public class MyService : IMyService
{// ...
}// 使用Source Generator自動生成注冊代碼
static partial class ServiceRegistration
{static partial void AddGeneratedServices(IServiceCollection services){services.AddTransient<IMyService, MyService>();}
}

.NET的依賴注入系統是框架的核心基礎設施,理解其原理和實現方式有助于編寫更可測試、更松耦合的應用程序。

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/91624.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/91624.shtml
英文地址,請注明出處:http://en.pswp.cn/web/91624.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

K8S部署ELK(二):部署Kafka消息隊列

目錄 1. Kafka 簡介 1.1 Kafka 核心概念 &#xff08;1&#xff09;消息系統 vs. 流處理平臺 &#xff08;2&#xff09;核心組件 1.2 Kafka 核心特性 &#xff08;1&#xff09;高吞吐 & 低延遲 &#xff08;2&#xff09;持久化存儲 &#xff08;3&#xff09;分…

Rust進階-part1-智能指針概述-box指針

Rust進階[part1]_智能指針概述&box指針 智能指針概述 在Rust中,智能指針是一類特殊的數據結構,它們不僅像普通指針一樣可以引用數據,還帶有額外的元數據和功能。與普通指針不同,智能指針通常使用結構體實現,并且會實現 Deref 和 Drop 等特定的trait,以提供更強大的…

C++擴展 --- 并發支持庫(補充1)

C擴展 --- 并發支持庫&#xff08;下&#xff09;https://blog.csdn.net/Small_entreprene/article/details/149606406?fromshareblogdetail&sharetypeblogdetail&sharerId149606406&sharereferPC&sharesourceSmall_entreprene&sharefromfrom_link atom…

在Three.js中導入和添加自定義網格的最佳實踐 - 綜合指南

探索在Three.js中導入和添加自定義網格的最佳實踐。本指南涵蓋增強 3D 項目的技術、技巧和實際示例。 添加圖片注釋&#xff0c;不超過 140 字&#xff08;可選&#xff09; 強烈建議使用 GLTF 格式來集成 3D 幾何體&#xff0c;提供簡化的流程&#xff0c;并固有地支持動畫、…

Redis知識點(1)

目錄 Redis Redis和MySQL的區別 Redis的高可用方案 Redis可以用來做什么 Redis的數據類型 字符串 列表 哈希 集合 有序集合 Bitmap Redis為什么快呢&#xff1f; I/O多路復用 說說select,poll,epoll,kqueue,IOCP的區別 Redis為什么早期選擇單線程&#xff1f; …

使用iptables封禁惡意ip異常請求

查看后端日志發現一IP&#xff08;103.76.250.29&#xff09;頻繁請求不存在的資源路徑??&#xff08;如 /api/v1/guest/comm/config、/theme/default/assets/compoments.js 等&#xff09;&#xff0c;并伴隨對根路徑 / 的正常訪問。這種行為的可能性包括惡意掃描、自動化工…

BehaviorTree.Ros2 編譯教程

1. 源碼下載 git clone https://github.com/BehaviorTree/BehaviorTree.ROS2.git2. 編譯過程 源碼中有3個項目: btcpp_ros2_interfacesbtcpp_ros2_interfacesbtcpp_ros2_samples 2.1 編譯btcpp_ros2_interfaces: colcon --packages-select btcpp_ros2_interfaces2.2 編譯 …

AR智能巡檢系統:制造業設備管理的效率革新

隨著工業4.0和數字化轉型的加速&#xff0c;設備管理在制造業、能源、交通等關鍵領域的重要性愈發凸顯。傳統設備巡檢依賴人工記錄和紙質報告&#xff0c;不僅效率低下&#xff0c;還容易因人為疏忽導致數據錯誤或安全隱患。然而&#xff0c;增強現實&#xff08;AR www.teamhe…

破解海外倉客戶響應難題:自動化系統是關鍵

在跨境電商蓬勃發展的當下&#xff0c;海外倉作為連接賣家與終端消費者的重要樞紐&#xff0c;其服務效率直接影響著賣家的運營成果。其中&#xff0c;即時客戶響應一直是行業痛點&#xff0c;尤其對中小型海外倉而言&#xff0c;單純依靠人力維持全天候服務意味著高昂的成本壓…

PyTorch基礎——張量計算

文章目錄PyTorch基礎——張量計算1 什么是張量計算&#xff1f;2 基本算術運算2.1 加法運算2.1.2 torch.add2.1.3 a.add(b) 與 a.add_(b)a.add(b) 方法a.add_(b) 方法核心區別2.2 減法運算2.2.1 toch.sub()2.2.2 a.sub(b) 和a.sub_(b)a.sub(b) 方法a.sub_(b) 方法核心區別使用建…

云原生聯調利器:Telepresence實戰

Telepresence在云原生聯調中的應用&#xff1a;本地服務直連K8s集群實戰在云原生開發中&#xff0c;調試和測試服務常常需要本地環境與遠程Kubernetes&#xff08;K8s&#xff09;集群無縫集成。Telepresence是一個開源工具&#xff0c;它允許開發者將本地服務“注入”到K8s集群…

瀏覽器【詳解】requestIdleCallback(瀏覽器空閑時執行)

簡介requestIdleCallback 是瀏覽器的一個 API&#xff0c;用于在瀏覽器空閑時間執行低優先級任務&#xff0c;避免阻塞主線程&#xff0c;提升頁面性能和響應速度。 當瀏覽器完成了關鍵任務&#xff08;如渲染、布局、用戶交互處理&#xff09;且暫時沒有更高優先級的工作時&am…

STP技術

一、環路的危害1.現象鏈路指示燈快速閃爍MAC表震蕩&#xff1a;交換機頻繁修改MAC地址表 → 轉發失效。2.環路危害造成的影響鏈路堵塞主機操作系統響應遲緩二層交換機管理緩慢沖擊網關設備的CPU三、STP的作用1.STP基本原理STP即生成樹協議&#xff0c;它通過阻斷冗余鏈路來消除…

RAGFLOW~knowledge graph

start 為了增強多跳問答&#xff0c;RAGFlow在數據提取和索引之間增加了一個知識圖譜構建步驟&#xff0c;如下面所示。這一步驟會從您指定的分塊方法生成的現有塊中創建額外的塊。 從v0.16.0版本開始&#xff0c;RAGFlow支持在知識庫上構建知識圖譜&#xff0c;允許你在知識庫…

機器學習【二】KNN

KNN算法是一種基于實例的惰性學習算法&#xff0c;其核心思想是通過"多數投票"機制進行分類決策。算法流程包括數據準備&#xff08;需歸一化處理&#xff09;、距離計算&#xff08;常用歐氏距離&#xff09;、選擇K值&#xff08;通過交叉驗證確定&#xff09;和決…

preloader

patch調試串口115200--- a/platform/ac8257/default.makb/platform/ac8257/default.mak-40,7 40,7 CFG_USB_DOWNLOAD :1CFG_FUNCTION_PICACHU_SUPPORT :1CFG_PMT_SUPPORT :0CFG_UART_COMMON :1 -CFG_LOG_BAUDRATE :921600 CFG_LOG_BAUDRATE :115200CFG_EVB_UART_CLOCK :260000…

Linux基礎(三)——Bash基礎

1、Bash基礎1.1 Bash簡介從前邊操作系統的組成介紹中&#xff0c;我們可以知道操作系統為上層用戶提供的與內核進行交互的接口稱為shell&#xff0c;其在系統中的位置如下圖所示&#xff0c;shell作為內核和用戶之間的中介&#xff0c;接收用戶發送的指令&#xff0c;將其解析為…

Python 元編程實戰:動態屬性與數據結構轉換技巧

在處理復雜嵌套的 JSON 數據源時&#xff0c;我們常面臨訪問不便、結構不靈活、字段關聯性差等問題。本文將以 O’Reilly 為 OSCON 2014 提供的 JSON 數據源為例&#xff0c;系統講解如何通過 動態屬性轉換、對象封裝、數據庫映射與特性&#xff08;property&#xff09;機制&a…

Android-側邊導航欄的使用

在學習之前&#xff0c;我們先得知道側邊導航欄是什么&#xff1f;它是一個 可以讓內容從屏幕邊緣滑出的布局容器&#xff0c;由安卓官方提供&#xff0c;用于創建側邊菜單&#xff0c;通常搭配 NavigationView 使用&#xff1b;添加依賴&#xff1a;在app下的build.gradle中添…

lesson30:Python迭代三劍客:可迭代對象、迭代器與生成器深度解析

目錄 一、可迭代對象&#xff1a;迭代的起點 可迭代對象的本質特征 可迭代對象的工作原理 自定義可迭代對象 二、迭代器&#xff1a;狀態化的迭代工具 迭代器協議與核心方法 迭代器的狀態管理 內置迭代器的應用 三、生成器&#xff1a;簡潔高效的迭代器 生成器函數&a…