编辑
2025-02-03
C# 应用
00
请注意,本文编写于 108 天前,最后修改于 108 天前,其中某些信息可能已经过时。

目录

引言
Nuget安装
创建特性
实现自动注入
完整示例
总结

在现代软件开发中,依赖注入(Dependency Injection, DI)是实现松耦合、模块化和可测试代码的一个重要实践。C# 提供了优秀的 DI 容器,如ASP.NET Core中自带的Microsoft.Extensions.DependencyInjection,但是有时候我们希望自定义一些功能,比如通过特性(Attributes)实现自动注入。本文将详细介绍如何从零开始实现一个通过特性自动注入的功能。

引言

特性(Attributes)是C#提供的一种用于在运行时通过反射向代码中添加声明性信息的方式。通过结合反射和特性,我们可以实现一种自动依赖注入的功能,这样可以简化DI的配置。

Nuget安装

C#
Microsoft.Extensions.DependencyInjection

创建特性

首先,我们需要创建一个特性,用于标记需要注入的类。

C#
using System; [AttributeUsage(AttributeTargets.Class, Inherited = false)] public sealed class InjectAttribute : Attribute { public ServiceLifetime Lifetime { get; } public InjectAttribute(ServiceLifetime lifetime = ServiceLifetime.Transient) { Lifetime = lifetime; } }

在这个示例中,InjectAttribute特性有一个可选参数Lifetime,用于指示依赖项的生命周期(如瞬时、作用域内或单例)。

实现自动注入

接下来,我们需要编写代码扫描程序集中的所有类型,并根据标记的特性注入依赖项。

C#
using Microsoft.Extensions.DependencyInjection; using System; using System.Linq; using System.Reflection; public static class ServiceCollectionExtensions { public static void AddServicesWithInjectAttribute(this IServiceCollection services, params Assembly[] assemblies) { var typesWithInject = assemblies .SelectMany(assembly => assembly.GetTypes()) .Where(type => type.GetCustomAttribute<InjectAttribute>() != null); foreach (var type in typesWithInject) { var injectAttribute = type.GetCustomAttribute<InjectAttribute>(); switch (injectAttribute.Lifetime) { case ServiceLifetime.Singleton: services.AddSingleton(type); break; case ServiceLifetime.Scoped: services.AddScoped(type); break; case ServiceLifetime.Transient: services.AddTransient(type); break; } } } }

在这个扩展方法中,AddServicesWithInjectAttribute会扫描传入的程序集,并根据InjectAttribute将相应的类型添加到DI容器中。

完整示例

为了完整演示如何使用上述功能,我们将创建一些示例代码。

C#
using Microsoft.Extensions.DependencyInjection; using System.Reflection; using System; namespace DependencyInjectionExample { // 定义一个服务接口 public interface IMyService { void DoWork(); } // 实现服务并标记 InjectAttribute [Inject(ServiceLifetime.Singleton)] public class MyService : IMyService { private Guid id { get; set; } public MyService() { id = Guid.NewGuid(); } public void DoWork() { Console.WriteLine("Service is working."+this.id); } } // 创建应用程序入口 class Program { static void Main(string[] args) { // 创建服务集合 var serviceCollection = new ServiceCollection(); // 自动注入服务 serviceCollection.AddServicesWithInjectAttribute(Assembly.GetExecutingAssembly()); // 构建服务提供者 var serviceProvider = serviceCollection.BuildServiceProvider(); // 解析服务并调用方法,指定使用 MyService1 var myService1 = serviceProvider.GetService<MyService>(); myService1.DoWork(); var myService2 = serviceProvider.GetService<MyService>(); myService2.DoWork(); } } }

在这个示例中,我们定义了IMyService接口和其实现MyService,并使用[Inject(ServiceLifetime.Singleton)]来标记MyService。在Main方法中,我们使用AddServicesWithInjectAttribute来自动扫描和注册服务,并最终通过依赖注入解析出服务并调用其方法。

image.png

总结

本文介绍了如何通过创建自定义特性与反射结合,实现一个简单的特性自动注入功能。在实际项目中,这种方式可以有效减少DI配置的冗余代码,提升开发效率。当然,这只是一个基础示例,实际应用中可以根据需要进行扩展和优化。

希望这篇文章对你有所帮助!如果有任何问题或建议,欢迎留言讨论。

本文作者:rick

本文链接:https://www.idiosoft.com/post/23

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

评论
  • 按正序
  • 按倒序
  • 按热度
来发评论吧~
Powered by Waline v2.14.8