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();
See more on this question at Stackoverflow