简体   繁体   中英

Why am I getting a System.InvalidCastException for my own types?

My method ImplementingInterface below, gets all of my own classes implementing my custom interface, 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.

}

But when it hit the line marked below with error occurs it throws the following error:

`An exception of type 'System.InvalidCastException' occurred in System.Core.dll but was not handled in user code

Additional information: Unable to cast object of type 'System.RuntimeType' to type 'ProjectPrefix.IInstaller'.`

expectedTypes has 3 classes that all implement IInstaller , why is it throwing this error?

You're searching for types - so your result is an IEnumerable<Type> . Those Type objects don't implement your interface - instances of the types would implement the interface.

So your code is trying to do something a little like:

IInstaller installer = typeof(SomeInstaller);

instead of:

IInstaller installer = new SomeInstaller();

If you want to be able to cast to the interface, you'll need to create instances of the types. If you're trying to dynamically create instances, and if they all have a public parameterless constructor, you could just use 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();

Or using Type.IsAssignableFrom :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM