我有一个接口IExample
,以及一组类ClassOne
,ClassTwo
和ClassThree
,它们都在不同的名称空间中定义。我可能会删除其中一个类,或者在开发的后期添加一个新类。
现在,我想找到在运行时实现IExample
的所有类型,并实例化它们。 (我事先知道实现IExample
的类不需要任何构造函数参数,但我不知道如何在代码中指定它,所以它是我 - 而不是编译器 - 知道...)
这可能吗?我该如何去做?
更新:我现在尝试了几种建议的方法,但是对于所有这些方法,Activator.CreateInstance(type)
行,我得到一个System.MissingMethodException,因为我“无法创建实例界面。“这是我的代码:
var tasks = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.GetTypes())
.Where(t => typeof(IBootstrapperTask).IsAssignableFrom(t))
// This line is where it fails
.Select(t => Activator.CreateInstance(t) as IBootstrapperTask)
.ToArray();
new AutoMapperBootstrapper(tasks).Initialize();
没有as
子句我没有看到任何异常,但我得到了object[]
,我需要IBootstrapperTask[]
作为摘录最后一行的构造函数。我尝试了各种方法来投射它,但似乎都没有。
答案 0 :(得分:29)
这可以通过Reflection完成。例如
var interfaceType = typeof(IExample);
var all = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(x => x.GetTypes())
.Where(x => interfaceType.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
.Select(x => Activator.CreateInstance(x));
注意:这只会在当前IExample
中加载的程序集中创建AppDomain
的实例。这可能与当前进程中加载的所有程序集不同。但是对于许多类型的应用程序,这将是等效的。
答案 1 :(得分:8)
您需要知道要查看的程序集列表,但LINQ使它相对容易:
var instances = (from assembly in assemblies
from type in assembly
where !type.IsAbstract &&
type.IsClass &&
type.IsPublic &&
!type.IsGenericType &&
typeof(IExample).IsAssignableFrom(type)
let ctor = type.GetConstructor(Type.EmptyTypes)
where ctor != null && ctor.IsPublic
select (IExample) Activator.CreateInstance(type))
.ToList();
您可能会想到要添加的其他一些限制,但它们很容易表达:)
instances
将成为List<IExample>
。
编辑:我怀疑我的代码会在你没有的地方工作,因为我特意排除非课程。我的猜测是你的代码试图实例化接口本身,即当t
为typeof(IBootstrapperTask)
时。
答案 2 :(得分:5)
你需要动态发生吗?有没有时候你可能有一个你不想创建的?在我看来,这是依赖注入(可以配置)的一个很好的例子。例如,Unity有一个ResolveAll方法。
从上面的链接;
IEnumerable<IMyObject> objects = myContainer.ResolveAll<IMyObject>();
答案 3 :(得分:0)
尝试使用反射来获取实现IExample
的类型。此示例查看当前程序集,但您可以轻松地传递不同的程序集:
IEnumerable<Type> types = Assembly.GetExecutingAssembly()
.GetTypes().Where(t=>t.GetInterfaces().Where(tt==typeof(IExample)).Count()>0);
List<object> objects = new List<object>();
foreach (Type type in types)
{
objects.Add(Activator.CreateInstance(type));
}