Поиск объектов, реализующих интерфейс из загруженной сборки - как сравнить типы?
У меня есть класс, который будет загружать все сборки в каталоге, а затем получить все типы посмотреть, реализуют ли они интерфейс. Я не могу заставить сравнение типов работать. В отладчике я вижу загруженный тип (тот, который мне интересен), если всегда не удается выполнить сравнение. Если я использую тот же код сравнения локально, проблем нет, я получаю ожидаемый результат. Я мог бы просто сравнить результаты на интерфейсах типов, но я бы предпочел знать, что я делаю неправильно.
тесты:
// Fails
[Fact]
public void FindISerialPortTest()
{
var path = Directory.GetCurrentDirectory();
var results = FindImplementers.GetInterfaceImplementor<ISerialPort>(path);
results.Length.Should().Be(1);
results[0].Should().BeAssignableTo<SerialPortWrapper>();
}
//Passes
[Fact]
public void DoesTypeImplementInterfaceTest()
{
var myType = typeof(SerialPortWrapper);
var myInterface = typeof(ISerialPort);
FindImplementers.DoesTypeImplementInterface(myType, myInterface).Should().Be(true);
}
Класс:
public class FindImplementers
{
public static T[] GetInterfaceImplementor<T>(string directory)
{
if (String.IsNullOrEmpty(directory)) { return null; } //sanity check
DirectoryInfo info = new DirectoryInfo(directory);
if (!info.Exists) { return null; } //make sure directory exists
var implementors = new List<T>();
foreach (FileInfo file in info.GetFiles("*.dll")) //loop through all dll files in directory
{
Assembly currentAssembly = null;
Type[] types = null;
try
{
//using Reflection, load Assembly into memory from disk
currentAssembly = Assembly.LoadFile(file.FullName);
types = currentAssembly.GetTypes();
}
catch (Exception ex)
{
//ignore errors
continue;
}
foreach (Type type in types)
{
if (!DoesTypeImplementInterface(type, typeof(T)))
{
continue;
}
//Create instance of class that implements T and cast it to type
var plugin = (T)Activator.CreateInstance(type);
implementors.Add(plugin);
}
}
return implementors.ToArray();
}
public static bool DoesTypeImplementInterface(Type type, Type interfaceType)
{
return (type != interfaceType && interfaceType.IsAssignableFrom(type));
}
}
1 ответ
Решение
ОК - это дало мне ответ: http://evolpin.wordpress.com/2012/11/11/invalidcastexception-when-using-assembly-loadfile/
Вот обновленный класс:
public class PluginLoader
{
public static T[] GetInterfaceImplementor<T>(string directory)
{
if (String.IsNullOrEmpty(directory)) { return null; } //sanity check
DirectoryInfo info = new DirectoryInfo(directory);
if (!info.Exists) { return null; } //make sure directory exists
var implementors = new List<T>();
foreach (FileInfo file in info.GetFiles("*.dll")) //loop through all dll files in directory
{
Assembly currentAssembly = null;
try
{
var name = AssemblyName.GetAssemblyName(file.FullName);
currentAssembly = Assembly.Load(name);
}
catch (Exception ex)
{
continue;
}
currentAssembly.GetTypes()
.Where(t => t != typeof(T) && typeof(T).IsAssignableFrom(t))
.ToList()
.ForEach(x => implementors.Add((T)Activator.CreateInstance(x)));
}
return implementors.ToArray();
}
}