在.net core中实现字段和属性注入的示例代码
var serviceType = serviceAttribute.ServiceType; if (serviceType == null && serviceAttribute.InterfaceServiceType) { serviceType = type.GetInterfaces().FirstOrDefault(); } if (serviceType == null) { serviceType = type; } switch (serviceAttribute.Lifetime) { case ServiceLifetime.Singleton: services.AddSingleton(serviceType, type); break; case ServiceLifetime.Scoped: services.AddScoped(serviceType, type); break; case ServiceLifetime.Transient: services.AddTransient(serviceType, type); break; default: break; } 我们首先检查serviceAttribute.ServiceType,如果有值的话,它就是注册服务的类型,如果没有的话,看是否允许从接口中获取服务类型,如果允许,便尝试获取第一个作为服务类型,如果还没获取到,就把自身的类型作为服务类型。 第一种情况不常见,特殊情况才会指定ServiceType,因为写起来麻烦; 第二种情况适用于依赖抽象编程的同学,注意这里只取第一个接口的类型; 第三种情况就是适用于像我这种有不良习惯的患者(依赖实现编程)! 到此为止我们的服务注册已经讨论完了,下面看看如何获取。 字段和属性注入 这里我们说的获取,不是框架默认容器提供的构造器注入,而是要实现字段和属性注入,先看看构造器注入是什么样的: public class HomeController : Controller { UserService userService; OrderService orderService; MsgService msgService; OtherService otherService; OtherService2 otherService2; public HomeController(UserService userService, OrderService orderService, MsgService msgService, OtherService otherService, OtherService2 otherService2) { this.userService = userService; this.orderService = orderService; this.msgService = msgService; this.otherService = otherService; this.otherService2 = otherService2; } } 如果引用的服务不再添加还好,如果编写边添加就太要命了,每次都要定义字段、在构造器方法签名中些添加参数、在构造器中赋值,便捷性和Spring的@autowired注解没法比,所以我们要虚心学习,创作更便捷的操作。 [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] public class AutowiredAttribute : Attribute { } 这个特性里面什么也没有,主要是下面这个类,装配操作都在这里: /// <summary> /// 从容器装配service /// </summary> [AppService] public class AutowiredService { IServiceProvider serviceProvider; public AutowiredService(IServiceProvider serviceProvider) { this.serviceProvider = serviceProvider; } public void Autowired(object service) { var serviceType = service.GetType(); //字段赋值 foreach (FieldInfo field in serviceType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { var autowiredAttr = field.GetCustomAttribute<AutowiredAttribute>(); if (autowiredAttr != null) { field.SetValue(service, serviceProvider.GetService(field.FieldType)); } } //属性赋值 foreach (PropertyInfo property in serviceType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { var autowiredAttr = property.GetCustomAttribute<AutowiredAttribute>(); if (autowiredAttr != null) { property.SetValue(service, serviceProvider.GetService(property.PropertyType)); } } } } 我们刚刚写的[AppService]特性在这里已经用上了,并且这个类使用构造器注入了IServiceProvider。Autowired(object service)方法的参数是要装配的服务实例,首先获取服务类型,再使用反射查询有AutowiredAttribute特性的字段和属性,我们在构造器注入了serviceProvider,这里便可以使用serviceProvider的GetService方法从容器中获取对应类型的实例来给字段和属性赋值。 整个过程就是这样,简单明了。开始的时候我想使用静态类来编写AutowiredService,但是静态类没法注入IServiceProvider,解决方法也有,可以使用定位器模式全局保存IServiceProvider: /// <summary> /// 服务提供者定位器 /// </summary> public static class ServiceLocator { public static IServiceProvider Instance { get; set; } } 在Setup的Configure方法中赋值: ServiceLocator.Instance = app.ApplicationServices; (编辑:晋中站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |