我想从解决方案文件夹中的多个程序集中检索实现接口的实例化类的枚举。
我有以下文件夹结构(如果这有意义的话):
Solution
-SolutionFolder
- Project1
- class implementing interface I would like to find
- other classes
- Project2
- class implementing interface I would like to find
- other classes
-MainProject
- classes where my code is running in which I would like to retrieve the list of classes
因此,如果要实现的接口是ISettings
,那么我希望IEnumerable<ISettings>
引用该接口的实例化对象。
到目前为止,我已经使用反射从一个已知的类名中检索实现接口的类:
IEnumerable<ISettings> configuration =
(from t in Assembly.GetAssembly(typeof(CLASSNAME-THAT-IMPLEMENTs-INTERFACE-HERE)).GetTypes()
where t.GetInterfaces().Contains(typeof(ISettings)) && t.GetConstructor(Type.EmptyTypes) != null
select (ISettings)Activator.CreateInstance(t)).ToList();
但这是一个单独的程序集,我实际上不会知道类名。
这可以通过反射实现吗?还是需要更多的东西?
只要你只谈论加载到AppDomain中的程序集(它们必须是这样才能完成你想要的任务),你就可以使用这样的东西来迭代它们:
AppDomain.CurrentDomain
.GetAssemblies().ToList()
.ForEach(a => /* Insert code to work with assembly here */);
或者,如果将它们加载到另一个AppDomain中,则可以使用一个实例来代替上面的AppDomain.CurrentDomain
。
为了解决这个问题,我在解决方案文件夹中设置了每个项目的后构建事件,以将其程序集复制到主项目bin文件夹中的bin文件夹中。
构建后事件设置为类似于:
copy "$(TargetPath)" "$(SolutionDir)MainProjectNamebin"
然后,我使用以下内容从这个bin目录中检索汇编文件名(Darin在这里发布了解决方案):
string[] assemblyFiles = Directory.GetFiles(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"), "*.dll");
然后,我检索了实现接口I设置的对象的实现,使用:
IEnumerable<ISettings> configuration = assemblyFiles.Select(f => Assembly.LoadFrom(f))
.SelectMany(a => a.GetTypes())
.Where(t => t.GetInterfaces().Contains(typeof(ISettings)) && t.GetConstructor(Type.EmptyTypes) != null)
.Select(t => (ISettings)Activator.CreateInstance(t));
这使我可以添加更多实现设置的项目,而无需重新编译主项目。
此外,我考虑的一个替代方案是使用MEF
,在这里可以找到介绍。