【问题标题】:Why am I getting a System.InvalidCastException for my own types?为什么我自己的类型会出现 System.InvalidCastException?
【发布时间】:2014-07-29 14:04:10
【问题描述】:

下面是我的方法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 标记的行时,它会抛出以下错误:

`System.Core.dll 中出现“System.InvalidCastException”类型的异常,但未在用户代码中处理

附加信息:无法将“System.RuntimeType”类型的对象转换为“ProjectPrefix.IInstaller”类型。`

expectedTypes 有 3 个类都实现了IInstaller,为什么会抛出这个错误?

【问题讨论】:

    标签: c# generics


    【解决方案1】:

    您正在搜索类型 - 所以您的结果是 IEnumerable&lt;Type&gt;。那些Type 对象没有实现您的接口 - instances 类型将实现该接口。

    所以你的代码正在尝试做一些类似的事情:

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

    【讨论】:

    • ....或者检查该类型是否使用该类型的方法之一实现了接口。你可以问一个实例是否会实现一个接口。
    • @TomTom:是的,我已经到了。但我想先纠正 OP 代码中最重要的部分 :)
    • @JonSkeet 谢谢我真是个白痴,只有一件事它把 IInstaller 作为其中一种类型,所以where 应该变成:.Where(t=&gt; interfaceType.IsAssignableFrom(t) &amp;&amp; t.GetConstructor(Type.EmptyTypes) != null)
    • @shenku:或者你可以检测类型是否是一个具体的类,这会让你找到所有没有有无参数构造函数但应该有的实现。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-29
    • 2014-06-28
    • 1970-01-01
    • 2013-11-16
    相关资源
    最近更新 更多