如果您想了解解决方案,请跳至更新:
我有一个应用程序,它使用以下代码来获取和运行许多工作方法
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();
}
此代码完美无缺。但是,一些较新的作业利用依赖注入来填充其构造函数,因此这种方法将无法继续使用。所以我想知道是否有办法以统一的方式做到这一点?
我最初的想法是,我将继续使用上半部分,然后使用resolve替换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类如下所示
事实证明,如果在Unity存在的情况下重新选择Assemblies,它将尝试反映到Unity的程序集中,如果由于缺少IServiceLocator的元数据扩展而使用ToList终结将引发异常。要解决此问题,在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();
}
答案 0 :(得分:2)
答案 1 :(得分:1)
在Unity中,您需要注意以下几项工作:
IEnumerable<T>
。ResolveAll
和InjectionConstructor
内注册时明确调用ResolvedArrayParameter
方法。这是一个演示应用程序:
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<JobContainerExtension>();
container.RegisterType<IService1, Service1>(new InjectionConstructor(
new ResolvedArrayParameter<IJob>(container.ResolveAll<IJob>().ToArray())));
container.RegisterType<IService2, Service2>(new InjectionConstructor(
new ResolvedArrayParameter<IJob>(container.ResolveAll<IJob>().ToArray())));
// End composition root
var service1 = container.Resolve<IService1>();
var service2 = container.Resolve<IService2>();
}
}
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<IJob> jobs;
public Service2(IEnumerable<IJob> jobs)
{
this.jobs = jobs;
}
}
}
答案 2 :(得分:0)
这是我的贡献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<Type>(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);
});
});