为什么我为自己的类型获取System.InvalidCastException?

时间:2014-07-29 06:00:56

标签: c# generics

下面的方法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,为什么会抛出此错误?

1 个答案:

答案 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();

或使用Type.IsAssignableFrom

return assembly.DefinedTypes
               .Where(t => interfaceType.IsAssignableFrom(t))
               .Select(t => Activator.CreateInstance(t))
               .Cast<TInterface>()
               .ToList();