Как собрать типы из текущего решения с помощью расширения Visual Studio?

Я создал пакет Visual Studio 2012 (используя VS2012 SDK). Это расширение (если оно установлено в среде IDE клиента) должно иметь, среди прочего, функциональность сбора всех определенных типов из текущего открытого решения, над которым работает разработчик. Аналогичная функция встроена в Visual Studio Designer для проекта приложения ASP.NET MVC, где разработчик реализует класс модели/контроллера, создает проект, а затем может получить доступ к этому типу в пользовательском интерфейсе Scaffolding (раскрывающийся список конструктора). Соответствующие функции также доступны в WPF, WinForms Visual Designers и т. д.

Допустим, мое расширение должно собрать все типы из текущего решения, которые реализуют интерфейс ISerializable. Шаги следующие: разработчик создает определенный класс, перестраивает содержащий проект/решение, затем выполняет некоторые действия, предусмотренные пользовательским интерфейсом расширения, таким образом, включает сбор ISerializabletypes.

Я попытался реализовать операцию сбора с использованием отражения:

List<Type> types = AppDomain.CurrentDomain.GetAssemblies().ToList()
                  .SelectMany(s => s.GetTypes())
                  .Where(p => typeof(ISerializable).IsAssignableFrom(p) && !p.IsAbstract).ToList();

Но приведенный выше код вызывает исключение System.Reflection.ReflectionTypeLoadException:

System.Reflection.ReflectionTypeLoadException was unhandled by user code
  HResult=-2146232830
  Message=Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.
  Source=mscorlib
  StackTrace:
       at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
       at System.Reflection.RuntimeModule.GetTypes()
       at System.Reflection.Assembly.GetTypes()
(...)  
LoaderException: [System.Exception{System.TypeLoadException}]
{"Could not find Windows Runtime type   'Windows.System.ProcessorArchitecture'.":"Windows.System.ProcessorArchitecture"}
(...)

Как я могу правильно реализовать операцию сбора определенных типов из текущего решения?


person sgnsajgon    schedule 02.10.2013    source источник
comment
Я нашел пример кода в соответствующей теме Поиск ProjectItem по имени типа через DTE Но этот итеративный подход очень и очень медленный. В моем решении VS с проектом около 60 этот код выполняется около дюжины секунд, поэтому это не совсем приемлемое решение. Я предполагаю, что это трудоемкая операция, но я считаю, что есть более быстрый способ достичь цели. Resharper и его модуль сбора типов делают эту работу быстрее во время инициализации.   -  person sgnsajgon    schedule 03.10.2013
comment
Есть радость от поиска решения?   -  person JDandChips    schedule 16.07.2014


Ответы (2)


Я пытался сделать то же самое, и, к сожалению, единственный способ обойти это, который я нашел до сих пор, - это сделать следующее (что, как мне кажется, немного беспорядочно, но, возможно, с некоторой настройкой для конкретной ситуации может быть в порядке)

var assemblies = AppDomain.CurrentDomain.GetAssemblies();
IEnumerable<Type> types = assemblies.SelectMany(x => GetLoadableTypes(x));

...

public static IEnumerable<Type> GetLoadableTypes(Assembly assembly)
{
    try
    {
        return assembly.GetTypes();
    }
    catch (ReflectionTypeLoadException e)
    {
        return e.Types.Where(t => t != null);
    }
}

Это даст вам все типы, но вы можете отфильтровать все, что пожелаете.

Ссылка на это сообщение: Как предотвратить ReflectionTypeLoadException при вызове Assembly.GetTypes()< /а>

person JDandChips    schedule 16.07.2014
comment
Я использовал модуль CodeDOM для обхода элементы решения внутри плагина VS, такие же, как в T4. Roslyn будет отличным решением, но пока оно находится на стадии бета-тестирования. Я понимаю, что невозможно собрать информацию о типах из плагина VS, используя стандартный механизм отражения, потому что эти типы решений не загружаются в AppDomain CLR плагина. Я знаю, что Resharper от Jetbrain использует собственный модуль синтаксического анализа и обхода, который может быть доступен с помощью API разработчиков R#. - person sgnsajgon; 17.07.2014

Я не уверен, правильно ли я вас понял, но если я это сделаю, это сделает это:

var assembly = Assembly.GetExecutingAssembly();
IEnumerable<Type> types = 
      assembly.DefinedTypes.Where(t => IsImplementingIDisposable(t))
                           .Select(t => t.UnderlyingSystemType);

........

private static bool IsImplementingIDisposable(TypeInfo t)
{
     return typeof(IDisposable).IsAssignableFrom(t.UnderlyingSystemType);
}
person NValchev    schedule 02.10.2013
comment
Этот фрагмент кода собирает только IDisposable типов, которые реализованы в той же сборке/проекте, в который он помещен, в сборке, которая является частью пакета. Но мне нужно собрать типы, которые реализованы в любом другом решении любого разработчика, установившего и использующего мой Package. Типы, которые не обязательно существуют в исходном коде и сборках моего пакета. - person sgnsajgon; 02.10.2013