2014-02-20 4 views
8

Я пишу компилятор, который генерирует сборки на диске .NET с использованием API System.Reflection.Emit. Сам компилятор построен против .NET 4.5, но сгенерированный код ссылается только на типы из Portable Class Libraries. Однако при попытке ссылаться на сгенерированную сборку из проекта Windows Phone 8 Visual Studio жалуется, что A reference to a higher version or incompatible assembly cannot be added to the project.Создание портативной библиотеки классов через Reflection.Emit

При открытии сгенерированной сборки в декомпиляторе я вижу, что она ссылается на два PCL плюс mscorlib 4.0.0.0, тогда как я понимаю, что PCL должны ссылаться на mscorlib 2.0.5.0.

Есть ли способ сделать API System.Reflection.Emit генерировать PCL, или это мой единственный вариант перехода на Mono.Cecil?

+0

Возможно, вы также захотите взглянуть на IKVM.Reflection, это позволит вам настроить таргетинг на другую версию фреймворка, чем текущая. – svick

+0

@svick Спасибо, я не знал, что IKVM имеет публичный API Emit. На первый взгляд, Mono.Cecil кажется лучше разработан. Есть ли какие-то причины, которые я должен предпочесть IKVM.Reflection? – Trillian

+0

API IKVM Reflection намеренно очень похож на нормальное отражение.Итак, если вы уже знаете это, вы сможете начать использовать его очень быстро. – svick

ответ

4

Хорошо, я отвечу на свой вопрос.

Я не нашел доказательств того, что API-интерфейсы System.Reflection.Emit могут создавать сборки, ссылающиеся на другую версию mscorlib, чем та, которая используется в текущем процессе. Действительно, API, которые принимают параметры System.Type и другие объекты отражения, предположительно добавляют ссылку на результат запроса своего свойства Type.Assembly, что соответствует используемой версии mscorlib.

Однако портативные библиотеки классов не отличаются от того, что генерирует System.Reflection.Emit, поэтому после сбоя можно исправить сборки, чтобы «сделать их переносимыми». Отказа от ответственности: это требует знакомства с форматом PE файла и может иметь непредсказуемые побочные эффекты, но это работает для меня:

  • При создании сборки, используйте AssemblyBuilder.SetCustomAttribute, чтобы добавить этот атрибут к сборке:

    [System.Runtime.Versioning.TargetFrameworkAttribute(".NETPortable,Version=v4.0,Profile=Profile136", FrameworkDisplayName = ".NET Portable Subset")] 
    
  • Это где он получает схематичен: после того, как называется AssemblyBuilder.Save, откройте файловый поток для чтения/записи сгенерированной сборки, пройти через PE, COFF, COM, CLI и таблицы метаданных заголовки, чтобы найти строку AssemblyRef таблицы за mscorlib. Измените ссылочную версию mscorlib на номер 2.0.5.0, добавьте 0x100 к своим флагам («перенастраиваемым») и обновите свой токен с открытым ключом до 0x7CEC85D7BEA7798E.

Обратите внимание, что если вы используете другие сборки фреймов, возможно, вам потребуется также исправить их ссылки (я не проверял это). В противном случае, вуаля! Теперь сборка переносима и может использоваться, например, в проекте Windows Phone.

(... или просто использовать Mono.Cecil/IKVM.Reflection ...)

Edit: Код я использовал можно найти on github. Это огромный взлом, поэтому обычные заявления об отказе от ответственности применяются на ваших собственных рисках.

+0

Поскольку похоже, что вы уже написали код, который модифицирует сборку, может быть разумно поделиться им. – svick

+0

@svick Я бы хотел, но это хорошая длина более 300 строк, плюс множество структур и перечислений. Я с удовольствием поделюсь им с тем, кто спрашивает меня об этом, хотя ... если есть что-то вроде PMs в stackoverflow. – Trillian

+1

Вы можете разместить его в pastebin. – zneak

Смежные вопросы