Настроить профили.NET Portable Class Library?
Мне нужно добавить и / или изменить профили, чтобы позволить большему количеству классов и членов совместно использоваться в PCL (многие из них встроены в каркас, такой как Thread.Sleep). Какой лучший способ сделать это? Есть ли инструменты, чтобы помочь этому?
PS: я не ищу ответа, чтобы сказать мне НЕТ или ОСТАНОВИТЬ. Я хочу иметь DLL-библиотеки компиляции один раз, которые могут совместно использоваться в другой среде. Нет бинарного кода для каждой платформы, нет перекомпиляции, нет ifdef.
Вот что я получил до сих пор:
Требование:
- Целевые среды: Silverlight 5 и.NET Framework 4.5.
- Назначение PCL: общая инфраструктура для клиента RIA и сервера ASP.NET (без WCF)
- Чего не хватает в профилях по умолчанию: XPath, Thread-методы, DynamicMethod/ILGenerator
Профили PCL: в разделе Справочные сборки \ Microsoft \ Framework.NETPortable:
- Все сборки являются заглушками с установленным атрибутом "Retargetable".
- Все сборки имеют флаги = 0x171: 0x001 подписано, 0x100 может быть перенаправлено, а 0x070 не определено в AssemblyNameFlags (похоже, не имеет никакого эффекта)
- Все ссылки между сборками также имеют атрибут "Retargetable".
- Все сборки с поддержкой Silverlight имеют версию 2.0.5.0.
- Встроенные двоичные файлы PCL содержат две ссылки для каждой из упомянутых сборок (например: mscorlib 2.0.5.0 retargetable + mscorlib 4.0)
Попытка настройки № 1
- Профиль: Silverlight 5 + .NET Framework 4.5 (профиль 24)
- Нужно скопировать SL5 mscorlib.dll в профиль 24
- Пометить SL5 mscorlib.dll как перезаписываемый (изменить на задержку с подписью)
- ReSharper: не удалось разрешить все методы расширения, ошибка в сопоставлении общего типа / значения
- Строй: успех, Пробег: успех
Попытка настройки № 2
- Профиль: Silverlight 5 + .NET Framework 4.5 (профиль 24)
- Скопируйте все SL5 DLL в профиль 24
- Пометить все библиотеки DLL SL5 как изменяемые (изменить задержку с подписью)
- Пометить все ссылки между библиотеками SL5 как переориентируемые
- ReSharper: не удалось разрешить все методы расширения, ошибка в сопоставлении общего типа / значения
- Строй: успех, Пробег: успех
Попытка настройки № 3
- Профиль: Silverlight 4 + .NET Framework 4.0.3 (профиль 18)
- Нужно скопировать SL4 mscorlib.dll в профиль 18
- Пометить SL4 mscorlib.dll как перезаписываемый (изменить задержку с подписью)
- ReSharper: успех
- Строй: успех, Пробег: успех
Попытка настройки № 4
- Профиль: Silverlight 4 + .NET Framework 4.0.3 (профиль 18)
- Скопируйте все SL4 DLL в профиль 18
- Установите версию.NET всех DLL-библиотек SL4 на v4 (у оригинальных DLL это не известно)
- Пометить все библиотеки DLL SL4 как изменяемые (изменить задержку с подписью)
- Пометить все ссылки между библиотеками SL4 как переориентируемые
- ReSharper: успех
- Строй: успех, Пробег: успех
Попытка настройки № 5 наследует № 4
- Профиль: Silverlight 4 + .NET Framework 4.0.3 (профиль 18)
- Добавьте System.Numerics SL4 (включенный в другие профили SL) в RedistList\FrameworkList.xml
- Добавьте System.Xml.XPath SL4 (не входит ни в какие профили SL) в RedistList\FrameworkList.xml
- Результат: не удалось разрешить System.Numerics и System.Xml.XPath из ссылок PCL по умолчанию
- Исправления: ссылки на обе библиотеки DLL вручную - невозможно заставить их перенаправить, хотя VS не будет компилироваться с неперезагружаемыми System.Numerics или System.Xml.XPath из-за указанной ниже проблемы
Заметки:
- Ошибка компиляции: "... определено в сборке, на которую нет ссылок, необходимо добавить ссылку на сборку". Происходит после того, как все сборки сделаны перенастраиваемыми, но одна из ссылок между ними не изменена на "перенастраиваемая"
Он работает в определенной степени, но довольно проблематично настраивать существующие ссылочные библиотеки DLL или добавлять новые, и при этом нельзя легко проверить код PCL после переопределения ссылочных библиотек (если вообще возможно).
2 ответа
Поскольку вы не примете НЕТ или СТОП в качестве ответа, позвольте мне объяснить, почему это плохая идея. Короткий ответ: если PCL не предоставляет API, обычно это происходит потому, что он не работает.
Прежде всего, у PCL нет собственного набора API. PCL просто показывает пересечения API-интерфейсов между заданным набором платформ, на которые вы хотите ориентироваться. Теперь есть случаи, когда пересечение уровня API дало бы больше API, чем то, что предоставляет PCL. Есть несколько причин, почему это может иметь место.
- API доступен не на всех платформах
- API доступен, но на самом деле не работает
- API определяется в разных сборках
Первый должен быть очевидным. Сам по себе PCL не является реальной платформой, а только показывает, что там есть. Поэтому мы не можем предоставить вам API, которые на самом деле не существуют на всех платформах, на которые вы ориентируетесь. Ведь мы выставляем перекресток.
Второй звучит немного странно, но на самом деле это происходит. Возьмем, к примеру, файл ввода-вывода в Windows Phone 7. Хотя класс File технически доступен в Windows Phone, он задокументирован как
Этот тип присутствует для поддержки инфраструктуры.NET Compact Framework в Silverlight для Windows Phone и не предназначен для использования в коде приложения.
Вы можете сказать "какое мне дело?" и просто попробуйте, но тогда вы обнаружите, что модель безопасности на телефоне будет препятствовать доступу к файлам, которые вы ищете. Так что разоблачение этого API в PCL не поможет. На самом деле, наша команда считает, что это действительно повредит вам, потому что ведет вас по непереносимому пути.
Третий вопрос, касающийся реализации API в разных сборках, немного сложнее. Чтобы понять, почему это проблема, вам нужно рассмотреть, как CLR обрабатывает API в целом. В CLR нет концепции загрузки отдельных типов, как, например, в Java. В.NET типы реализованы в сборках, и для их использования ("загрузить их") необходимо загрузить сборку, которая определяет тип. Под обложками ссылки на типы включают в себя и имя, уточненное в пространстве имен, и сборку, в которой определен тип. Как правило, типы, имеющие одно и то же квалифицированное имя пространства имен, но находящиеся в разных сборках, считаются разными. Например, тип MyNamespace.MyType, Assembly1
а также MyNamespace.MyType, Assembly2
, Обратите внимание, что сами сборки также имеют понятие полностью определенного имени; включает имя сборки и токен открытого ключа. Это позволяет двум компаниям создавать обе сборки под названием "Foo" и не путать CLR (при условии, конечно, что они подписаны разными ключами). Таким образом, в сущности, загрузка типа требует нескольких шагов: поиск сборки, в которой определен тип, загрузка этой сборки, а затем загрузка типа.
Обычно разные платформы.NET используют разные ключи для сборок платформы, например, mscorlib. Теперь вы можете задаться вопросом, как вы можете использовать типы из Silverlight в.NET Framework. Причина этого в том, что в CLR есть концепция объединения сборок. Раскрытие сборки позволяет.NET Framework обрабатывать ссылки на mscorlib в Silverlight как ссылки на настольную версию. Это верно, потому что mscorlib Silverlight был разработан как подмножество версии.NET Framework (для определенной комбинации версий).
Хотя это может звучать как серебряная пуля для преодоления всех различий в форме пальца, на самом деле это не так. Со временем разные платформы выбрали разные сборочные коэффициенты. Взять, к примеру, ICommand. Он доступен в.NET 4 и Silverlight 4. Однако в WPF он реализован в PresentationCore.dll, а Silverlight - в System.Windows.dll. Чтобы понять, почему PCL не предоставляет ICommand, когда вы ориентируетесь на.NET 4 и Silverlight 4, давайте посмотрим, что произойдет, если PCL представит его.
В PCL мы должны поместить ICommnad в какую-то сборку. Мы могли бы либо использовать сборку Silverlight, либо полную сборку. Независимо от того, какой из них мы выберем, тип не будет разрешен на другой платформе, поскольку PresenationCore.dll существует только в.NET 4, а System.Windows.dll существует только в Silverlight 4.
Мы решили эту проблему, позволив ссылкам для ICommand в System.Windows.dll успешно работать в полной структуре. Как мы это сделали? Ответ - переадресация типа. Переадресация типов позволяет сборке сказать "я определяю тип Foo". Когда CLR пытается загрузить тип Foo из этой сборки, сборка фактически говорит "нет, нет - тип Foo фактически определен в этой другой панели сборки". Другими словами, сборка Foo содержит что-то вроде указателя на версию типа Bar. Мы называем эти записи типа переадресации указателей.
Эта концепция позволила нам решить проблему несоответствия ICommand, добавив System.Windows.dll в полную структуру, содержащую тип, перенаправляющий в фактическую реализацию. PCL теперь предоставляет ICommand в System.Windows.dll и может быть уверен, что запросы на загрузку типов могут выполняться как на.NET Framework, так и на Silverlight. Это, однако, требует нацеливания как минимум на.NET Framework 4.5, так как в предыдущих версиях не было типа forward.
Для всех API, которые должны быть представлены, но не мы работаем вместе с владельцами платформы, чтобы закрыть пробелы. У нас есть две основные стратегии для этого:
- Мы просим владельцев платформ добавить отсутствующие API или напечатать
- Мы поставляем портативную реализацию по внешнему виду. Взять, к примеру, Async или HttpClient.
Однако "просто" добавление его в PCL не работает.
РЕДАКТИРОВАТЬ: Если вы пропустите функцию в PCL, вы всегда можете разблокировать себя. Наш тестировщик Даниэль написал пост в блоге, который показывает несколько методов, которые вы можете использовать.
NO. СТОП.
Хорошо, так как это не то, что вы хотите услышать, продолжайте на свой страх и риск.:) Это, конечно, не поддерживается, и IANAL, поэтому я не знаю, будет ли это разрешено лицензионным соглашением.
Похоже, что основная проблема, с которой вы столкнулись в своих существующих решениях, заключается в том, что вы не можете выбрать отдельные API для добавления в переносимый профиль. Для этого вы можете использовать ildasm в существующих ссылочных сборках, затем добавить нужные API-интерфейсы (возможно, скопировав их из результатов выполнения ildasm в другой ссылочной сборке), а затем использовать ilasm для создания своих собственных версий ссылок. сборки с этими дополнительными API.
Вам нужно будет отложить подпись и / или отключить проверку ключа строгого имени для ключей для сборок, которые вы изменяете таким образом.
Другой вариант - использовать переадресацию, как описано в моем ответе здесь. В этом случае ваш основной код будет доступен для совместного использования, как есть, с зависимостью от DLL, которая будет отличаться для каждой платформы.