System.Reflection — глобальные методы недоступны для отражения

System.Reflection не поддерживает (AFAIK) отражение глобальных методов в сборке. На уровне сборки я должен начать с корневых типов.

Мой компилятор может создавать сборки с глобальными методами, а моя стандартная загрузочная библиотека представляет собой dll, включающую некоторые глобальные методы. Мой компилятор использует System.Reflection для импорта метаданных сборки во время компиляции. Кажется, если я завишу от System.Reflection, глобальные методы невозможны. Самое чистое решение — преобразовать все мои стандартные методы в статические методы класса, но дело в том, что мой язык допускает глобальные методы, и CLR поддерживает это, но System.Reflection оставляет пробел.

ildasm прекрасно показывает глобальные методы, но я предполагаю, что он не использует саму System.Reflection и переходит прямо к метаданным и байт-коду.

Помимо System.Reflection, кто-нибудь знает о каких-либо других сторонних библиотеках для отражения или дизассемблирования, которые я мог бы использовать (при условии, что в конечном итоге я выпущу свой компилятор как бесплатный, с открытым исходным кодом под лицензией BSD).

РЕШЕНО: Нет никакого пробела, кроме как в моих знаниях. Спасибо, что указали на GetModules, ребята!


person codenheim    schedule 22.04.2010    source источник


Ответы (3)


Вы просматривали Module.GetMethods?

Возвращает глобальные методы, определенные в модуле

Вы можете получить все модули вашей сборки, используя Assembly.GetModules().

person Jon Skeet    schedule 22.04.2010
comment
Побей меня, но я должен признать, что я на самом деле не пробовал. Хороший вопрос и хороший ответ. - person Brian Rasmussen; 23.04.2010
comment
у вас, вероятно, есть некоторая сила высокого уровня, которая позволит вам узнать, точна ли документация или нет, просто взглянув на нее :) - person Brian Rasmussen; 23.04.2010
comment
У меня есть MSDN + стол, полный справочников по компиляторам и .NET, включая Expert .NET 2.0 IL Assembler, и я до сих пор скучаю по таким вещам, смущающим. :| - person codenheim; 23.04.2010

Вы продолжаете бороться с разрывом между CLR и System.Reflection, но на самом деле не существует такой вещи, как глобальный метод или глобальное поле.

Это просто традиционные статические методы и статические поля, которые определены в определенном типе с именем <Module>, который должен присутствовать в каждой допустимой сборке.

Как сказал Джон, вы можете использовать Module.GetMethod и Module.GetField для операторов членов типа.

Если вам нужен больший контроль, вы можете просто использовать Mono.Cecil.

person Jb Evain    schedule 22.04.2010
comment
Я не бью ни по чему, кроме своей клавиатуры. Я просто пропустил эту информацию, поэтому и спросил на SO. Я узнаю больше каждый день. Спасибо за ответ. :) - person codenheim; 23.04.2010
comment
@Jb: Что касается Mono.Cecil, я знаю об этом и, безусловно, заинтересован в этом. Единственная причина, по которой я его пропустил, — это лицензия. Когда я выпущу свой код, это будет лицензия BSD. Я буду поддерживать сборку с помощью Mono, но я не могу включать зависимости от каких-либо инструментов, которые не являются общими для официальных CLR и Mono. Конечно, сейчас это все спекулятивно. - person codenheim; 23.04.2010
comment
@mrjoltcola: Mono.Cecil распространяется под лицензией MIT/X11 (аналогично BSD), так что это не должно быть проблемой. - person Jb Evain; 23.04.2010
comment
Существует существует такая вещь, как глобальный метод, вы просто не можете получить к нему доступ с помощью C#/VB. Вы можете создать его вручную, используя ModuleBuilder.DefineGlobalMethod. Они не хранятся в <Module>, просто Reflector делает их видимыми. Также см. stackoverflow.com/questions/3796688/whats-a-global-method. - person Abel; 19.03.2012
comment
@Абель, ты не прав. Здесь Reflector показывает, как они хранятся в сборке, то есть в типе <Module>. - person Jb Evain; 19.03.2012
comment
Попробуйте ILDASM в своем классе. Вы не найдете тип <Module>. Он там неявно и обозначает глобальные методы. cctor <Module> загружается, когда загружается модуль (т. е. сборка) (это конструктор модуля). Любой метод в этом разделе можно вызывать без указания класса. Вы ссылаетесь на Reflector, и я тоже его использую, но он показывает его так, как он это делает, для удобства. Это представление, а не фактический источник (попробуйте скомпилировать System.Data туда и обратно, у вас ничего не получится). См. Также ответ Джона: как вы думаете, почему MS называет их глобальными методами? - person Abel; 19.03.2012
comment
Уважаемый @Abel, как автор библиотеки для чтения и записи сборок .net (Mono.Cecil) вне Reflection, я думаю, что имею представление о том, как типы и методы сериализуются в метаданных. Глобальные методы и поля — это просто соглашение для методов и полей, прикрепленных к типу ‹Module› (первый и обязательный скрытый тип сборок). Прочтите ECMA-335 и откройте сборку в ildasm, показывающую таблицы и строки метаданных, чтобы на самом деле понять, что скрывается за соглашением, которое использует ildasm. Спасибо. - person Jb Evain; 19.03.2012
comment
Спасибо, что нашли время, чтобы объяснить мне это дальше. Я в курсе стандарта. Я предполагаю, что вы имеете в виду раздел 10.8, в котором говорится о глобальных полях и методах, хранящихся в невидимом абстрактном общедоступном классе. Я был не прав, говоря, что типа <Module> там нет, я вижу его и в бинарнике (думал, что он там неявно, мой плохой). Но все же это понятие глобальных членов, где имя члена должно быть уникальным между загружаемыми модулями, иначе произойдет ошибка. Как это не может быть глобальным? - person Abel; 19.03.2012

Обратите внимание, что Module.GetMethod() без параметров не вернет все методы модуля.
Вместо этого используйте GetMethods(BindingFlags).

Пример С++/CLI:

#using <System.dll>
using namespace System;
using namespace System::Reflection;
using namespace System::Diagnostics;

bool has_main(array<MethodInfo^>^ methods)
{
    for each(auto m in methods)
        if(m->Name == "main")
            return true;
    return false;
}

int main()
{
    auto module = Assembly::GetExecutingAssembly()->GetModules(false)[0];
    Debug::Assert(has_main(module->GetMethods()) == false);
    Debug::Assert(has_main(module->GetMethods(BindingFlags::Static | BindingFlags::NonPublic)));
}
person Abyx    schedule 08.03.2011