Любой способ "безопасно" вызывать сборку .GetTypes()?
Я искал высоко и низко, но я не могу найти решение для этого.
Мне нужно получить все типы интерфейсов из сборки с таким кодом:
IEnumerable<Type> interfaces = _assembly.GetTypes().Where(x => x.IsInterface);
Проблема в том, что для некоторых сборок я сталкиваюсь с следующей ошибкой:
Невозможно загрузить один или несколько из запрошенные типы. Извлеките Свойство LoaderExceptions для более информация.
Я полностью понимаю, почему это происходит (зависимые сборки не загружаются) и как его можно обойти, если я хочу устранить неполадку конкретной сборки. В моем случае я не знаю сборку спереди (пользователь ее выберет).
То, что я хотел бы знать, заключается в том, есть ли способ разрешить код продолжать какие-либо типы, которые не могут быть получены, и по-прежнему вытаскивать те, которые не терпят неудачу.
Ответы
Ответ 1
Похоже, что это досадный API, для которого исключение нельзя избежать (насколько я знаю).
Попробуйте что-то вроде этого:
IEnumerable<Type> interfaces;
try
{
interfaces = _assembly.GetTypes().Where(x => x.IsInterface);
}
catch (ReflectionTypeLoadException ex)
{
interfaces = ex.Types.Where(x => x != null && x.IsInterface);
}
UPDATE
Собственно, это так уродливо, что я, вероятно, спрячу его где-нибудь. Это должно быть очень старой частью .NET Framework, потому что Im очень уверен, что они не будут создавать его так, как сейчас.
private static IEnumerable<Type> GetTypesSafely(Assembly assembly)
{
try
{
return assembly.GetTypes();
}
catch(ReflectionTypeLoadException ex)
{
return ex.Types.Where(x => x != null);
}
}
...
IEnumberable<Type> interfaces = GetTypesSafely(_assembly).Where(x => x.IsInterface);
Если вы думаете, что будете делать это очень часто, то метод расширения может быть более уместным.
Ответ 2
Обрабатывать исключение в другом методе, который заменяет собой выражение лямбда и ловит исключение. Вы также можете иметь исключения, которые накапливаются в каком-либо глобальном объекте для проверки позже.
IEnumerable<Type> interfaces = _assembly.GetTypes().Where(IsInterface);
List<string> Messages = new List<string>();
private bool IsInterface(Type x)
{
try { return x.IsInterface; }
catch (Exception e)
{
Messages.Add(e.Message);
}
return false;
}