下面的方法ImplementingInterface
,让我自己的所有类都实现自定义界面IInstaller
。
private static IEnumerable<Assembly> MyAssemblies
{
get { return AppDomain.CurrentDomain.GetAssemblies().Where(x=>x.GetName().Name.StartsWith("ProjectPrefix", StringComparison.OrdinalIgnoreCase)); }
}
public static IEnumerable<TInterface> ImplementingInterface<TInterface>() where TInterface : class
{
var interfaceType = typeof(TInterface);
if (!interfaceType.IsInterface)
throw new Exception(interfaceType.Name + " is not an interface.");
var types = new List<Type>();
foreach (var assembly in MyAssemblies)
{
types.AddRange(assembly.DefinedTypes.Where(x => x.ImplementedInterfaces.Any(inter => inter == interfaceType)));
}
var expectedTypes = types.ToList();
var interfaces = expectedTypes.Cast<TInterface>().ToList(); // Error occurs.
}
但当它点击下面标有error occurs
的行时,会抛出以下错误:
`类型&#39; System.InvalidCastException&#39;的例外。发生在System.Core.dll中但未在用户代码中处理
其他信息:无法投射类型&System; RuntimeType&#39;输入&#39; ProjectPrefix.IInstaller&#39; .`
expectedTypes
有3个类都实现IInstaller
,为什么会抛出此错误?
答案 0 :(得分:4)
您正在搜索类型 - 因此您的结果是IEnumerable<Type>
。那些Type
个对象没有实现您的界面 - 类型的实例将实现该界面。
所以你的代码试图做一些像:
IInstaller installer = typeof(SomeInstaller);
而不是:
IInstaller installer = new SomeInstaller();
如果您希望能够转换为界面,则需要创建类型的实例。如果您尝试动态创建实例,并且它们都有公共无参数构造函数,则可以使用Activator.CreateInstance
:
// Get rid of the AddRange call... there's no point in that, or calling
// ToList() on something that's already a list. Use LINQ to its fullest :)
return assembly.DefinedTypes
.Where(t => t.ImplementedInterfaces.Contains(interfaceType))
.Select(t => Activator.CreateInstance(t))
.Cast<TInterface>()
.ToList();
return assembly.DefinedTypes
.Where(t => interfaceType.IsAssignableFrom(t))
.Select(t => Activator.CreateInstance(t))
.Cast<TInterface>()
.ToList();