Posts Tagged ‘type forwarding’
Коротко про type forwarding
Представьте, что у вас есть SDK, состоящий из огромного количества библиотек, и что любому пользователю вашего SDK нужно для нормальной работы подключить штук 15-20 DLLек, причем конечный пользователь может даже не знать заранее, какие именно библиотеки нужны. Эта ситуация – весьма неприятная. Все мы знаем, что Visual Studio 2010 добавляет новые ссылки на библиотеки с черепашьей скоростью, и что трудозатраты по добавлению ссылок равны факториалу (!!!) от количества ссылок которые вы добавляете.
Очевидно, нужно искать возможность как-то улучшить user experience. Не имея возможности просто сделать ILMerge на все сборки, у нас тем не менее есть возможность сделать нечто не менее эффективное – а именно создать прокси-сборку для всех типов внутри сборок, и воспользоваться фичей под названием type forwarding, для того чтобы вызывались именно конечные сборки нашего SDK.
Как работает type forwarding?
Поддержка type forwarding была добавлена в .Net 2.0 для того чтобы авторы библиотек могли мигрировать типы из одной сборки в другую, не ломая в процессе код пользователей и не требуя перекомпиляции.
Вот как это работает. Есть у меня сборка FirstAssembly, а в ней тип С:
// FirstAssembly.dll
public class С {}
Далее, другой пользователь пишет свой код, ссылаясь на FirstAssembly.dll:
С с = new С();
Все хорошо, но вдруг я решил передвинуть мой тип C в сборку SecondAssembly.dll, при этом не меняя пространства имен и имени самого типа. Тогда я делаю следующее:
- Удаляю реализацию класса
СвFirstAssembly.dllи переношу его вSecondAssembly.dll - Добавляю ссылку на
SecondAssembly.dllвFirstAssembly.dll - Иду в
FirstAssembly, открываю тамAssemblyInfo.csи в нем пишу магическую строчку
[assembly: TypeForwardedTo(SomeNamespace.C)]
Эта директива намекает пользователям, что де типCпереехал, и теперь находится в другой сборке.
Атрибут сборки на момент компиляции FirstAssembly.dll превращается в следующую директиву:
.class extern forwarder SomeNamespace.C
{
.assembly extern SecondAssembly
}
Иначе говоря, все, что у нас получается – это лишняя директива которая подсказывает, что если клиент ищет в нашей сборке тип Somenamespace.C но не находит его, имеет смысл поискать этот тип в сборке SecondAssembly.dll.
Обсуждение
Во-первых, следует заметить что какой-то особой поддержки type forwarding со стороны Visual Studio не существует – в лучшем случае, при попытке сослаться на тип из сборки который «переехал», помимо обычной ошибки Visual Studio намекнет вам, что тип «мигрировал» и что для успешной компиляции вам стоит добавить ссылку на SecondAssembly.dll.
В контексте SDK, следует заметить, что
- Вы не можете просто поставлять набор из огромного количества директив
TypeForwardedToи компилировать код. В момент компиляции нужны ссылки на реальные сборки или же на некие прокси, которые в точности повторяют структуру тех сборок, на которые нужно ссылаться. - В момент исполнения, мы не можем «выкинуть» прослойку, т.к. тогда непонятно откуда брать информацию о местоположении реальных сборок.
- Фактически, требуются две прокси-сборки. Одна – это прокси для компиляции, вторая – с набором директив type forwarding для исполнения.
Теперь я пытаюсь понять, правильный ли это подход, и если да – как заставить Mono.Cecil делать из «реальных» сборок прокси с пустышками вместо методов. ▪
