65.9K
CodeProject 正在变化。 阅读更多。
Home

.Net Core DI,如何注册程序集中所有可赋值的类型

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2020年1月14日

CPOL

2分钟阅读

viewsIcon

21246

在本文中,我们将解释如何在程序集中注册(添加)所有特定接口可赋值的类型,并在一个类中使用它们。

引言

.Net Core 带有它自己的依赖注入容器,并且 .Net Core 3.0 表明 .Net Core DI 可以是可靠和高效的。它仍然存在一些缺点。有很多扩展可以修复这些缺点,从而提供绝佳的机会。基本上,.Net core 使得编写和扩展它变得容易。

在本文中,我将向您展示如何添加一个新的扩展来注册所有可赋值于特定接口(类:接口)的类型。
如果您有用于某个任务的不同逻辑,并希望将它们存储在不同的类中并通过配置加载它们,这将很有帮助。

背景

假设您有特定的逻辑来计算员工的税款,并且您有几种类型的员工,每种员工类型都有自己的逻辑。因此,您将拥有一个接口,并且每种员工类型都应实现该接口。用户应该具有添加新员工类型的特性,这意味着用户还需要为新的员工类型添加新的逻辑。因此,基于开闭原则,我们不希望打开主代码进行更改,但我们需要为用户提供添加新逻辑的方式。因此,我们添加一个接口层和一个项目来添加新类。当用户添加新逻辑时,他应该重新启动应用程序,DI 将加载该项目中实现该接口的所有类。在这里,我们漂亮的扩展将发挥作用。

使用代码

正如您所看到的,该扩展非常简单易用,但它正在发挥魔力;)

public static class RegisterAllAssignableTypes
{
   public static void RegisterAllAssignableType<T>(this IServiceCollection services, string assemblyName)
   {
      var assembly = AppDomain.CurrentDomain.Load(assemblyName);
      var types = assembly.GetTypes().Where(p => typeof(T).IsAssignableFrom(p)).ToArray();

       var addTransientMethod = typeof(ServiceCollectionServiceExtensions).GetMethods().FirstOrDefault(m =>
           m.Name == "AddTransient" &&
           m.IsGenericMethod == true &&
           m.GetGenericArguments().Count() == 2);

       foreach (var type in types)
       {
          if (type.IsInterface)
             continue;

          var method = addTransientMethod.MakeGenericMethod(new[] { typeof(T), type });
          method.Invoke(services, new[] { services });
       }
   }

   public static Interface ResolveByName<Interface>(this IServiceProvider serviceProvider, string typeName)
   {
      var allRegisteredTypes = serviceProvider.GetRequiredService<IEnumerable<Interface>>();
      var resolvedService = allRegisteredTypes.FirstOrDefault(p => p.GetType().FullName.Contains(typeName));

      if (resolvedService != null)
      {
         return resolvedService;
      }
      else
      {
         throw new TypeNotFound($"{typeName} type not found.");
      }
   }
}

 

第一种方法 RegisterAllAssignableTypes 将在您配置 Dot Net core DI 时使用。因此,您将有一行代码如下所示

    services.RegisterAllAssignableType<ITaxCalculator><itaxcalculation>("MyApp.ExtendedLogics");

它将读取 MyApp.Extended 项目中实现 ITaxCalculator 的所有类,并将它们作为 Transient 注册到 DI 容器中。

因此,在消费者类中,您只需要将 IServiceProvider 添加到构造函数中即可。

    public class EmployeeProcess
    {
        private readonly IServiceProvider _serviceProvider;
    
        public(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
    }

现在,当您从数据库加载员工并知道其类型时,您可以通过此扩展方法轻松加载其税收计算逻辑

    var employeeType = employee.Type;
    var employeeTaxLogic = _serviceProvider.ResolveByName<itaxcalculator>(employeeType);
    
    var tax = employeeTaxLogic.CalculateTax(employee);
</itaxcalculator>

关注点

我更多地了解了 .Net Core DI,这似乎将在 .Net 应用程序中成为新一代。

历史

您可以通过 NuGet 访问此代码:MOME.DotNetDIExtensions

如果您使用它并报告其问题并推荐您的想法,以了解我们如何改进它以及您需要的 DI 扩展,我将非常高兴。这样,我可以将它们添加到此包中并开发和改进它。

© . All rights reserved.