获取在Unity中实现接口的所有类型

如果您想了解解决方案,请跳至更新:

我有一个应用程序,它使用以下代码来获取和运行许多工作方法

var type = typeof(IJob); var types = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(x => x.GetTypes()) .Where(x => x.IsClass && type.IsAssignableFrom(x)); foreach (Type t in types) { IJob obj = Activator.CreateInstance(t) as IJob; obj.Run(); } 

此代码完美无缺。 但是,一些较新的作业利用dependency injection来填充其构造函数,因此这种方法将无法继续使用。 所以我想知道是否有办法以统一的方式做到这一点?

我最初的想法是,我将继续上半部分,然后用解决方案替换foreach逻辑,使其看起来像下面这样。

 var type = typeof(IJob); var types = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(x => x.GetTypes()) .Where(x => x.IsClass && type.IsAssignableFrom(x)); foreach (Type t in types) { IJob obj = Container.Resolve(t) as IJob; obj.Run(); } 

问题是,一旦我定义了UnityContainer,实现IJob的返回类型列表突然变得臃肿,所有这些垃圾Microsoft.Practices类如下所示

在此处输入图像描述

更新:

事实certificate,如果在Unity存在的情况下重新选择Assemblies,它将尝试反映到Unity的程序集中,如果由于缺少IServiceLocator的元数据扩展而使用ToList终结将引发exception。 要解决此问题,在GetAssemblies()之后附加一个where子句以将范围限制到所需的命名空间将允许应用程序正常运行。

 var type = typeof(IJob); var types = AppDomain.CurrentDomain.GetAssemblies() .Where(x => x.FullName.StartsWith("YourNamespace")) .SelectMany(x => x.GetTypes()) .Where(x => x.IsClass && type.IsAssignableFrom(x)); foreach (Type t in types) { IJob obj = Container.Resolve(t) as IJob; obj.Run(); } 

而不是搜索所有程序集,而是通过自定义属性过滤它们。 这样你就可以大大缩小搜索范围。

这是如何创建自定义程序集级别属性

自定义assembly属性

在Unity中,您需要注意以下几项工作:

  1. 您需要使用其他名称注册每个实例。 未命名的实例无法解析为数组或IEnumerable
  2. ResolveAllResolvedArrayParameter中注册期间,必须显式调用ResolveAll方法。

这是一个演示应用程序:

 using Microsoft.Practices.Unity; using System; using System.Collections.Generic; using System.Linq; namespace UnityExperiment { class Program { static void Main(string[] args) { // Begin composition root var container = new UnityContainer(); container.AddNewExtension(); container.RegisterType(new InjectionConstructor( new ResolvedArrayParameter(container.ResolveAll().ToArray()))); container.RegisterType(new InjectionConstructor( new ResolvedArrayParameter(container.ResolveAll().ToArray()))); // End composition root var service1 = container.Resolve(); var service2 = container.Resolve(); } } public class JobContainerExtension : UnityContainerExtension { protected override void Initialize() { var interfaceType = typeof(IJob); var implementationTypes = AppDomain.CurrentDomain.GetAssemblies() .Where(x => x.FullName.StartsWith("UnityExperiment")) .SelectMany(x => x.GetTypes()) .Where(x => x.IsClass && interfaceType.IsAssignableFrom(x)); foreach (Type implementationType in implementationTypes) { // IMPORTANT: Give each instance a name, or else Unity won't be able // to resolve the collection. this.Container.RegisterType(interfaceType, implementationType, implementationType.Name, new ContainerControlledLifetimeManager()); } } } public interface IJob { } public class Job1 : IJob { } public class Job2 : IJob { } public class Job3 : IJob { } public interface IService1 { } public class Service1 : IService1 { private readonly IJob[] jobs; public Service1(IJob[] jobs) { this.jobs = jobs; } } public interface IService2 { } public class Service2 : IService2 { private readonly IEnumerable jobs; public Service2(IEnumerable jobs) { this.jobs = jobs; } } } 

这是我的贡献fellas:

 //Register all IJob implementations that are not generic, abstract nor decorators Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "SomeFilter*.dll") .Select(file => Assembly.LoadFile(file)) .ForEach(s => { s.GetTypes() .Where(type => typeof(IJob).IsAssignableFrom(type) && (!type.IsAbstract && !type.IsGenericTypeDefinition)) .Select(type => new { type, ctor = type.GetConstructors().Any(ct => ct.GetParameters().Any(p => p.ParameterType == typeof(IJob))) == false }) .Select(type => type.type) .ForEach(o => { string jobFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, string.Format("{0}.xml", Path.GetFileNameWithoutExtension(o.Assembly.Location))); var typeLoadHelper = new SimpleTypeLoadHelper(); typeLoadHelper.Initialize(); XMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(typeLoadHelper); processor.AddJobGroupToNeverDelete("XMLSchedulingDataProcessorPlugin"); processor.AddTriggerGroupToNeverDelete("XMLSchedulingDataProcessorPlugin"); processor.ProcessFileAndScheduleJobs(jobFile, jobFile, this.Scheduler); }); });