Дмитpий Hecтepук

Блог о программировании — C#, F#, C++, архитектура, и многое другое

Posts Tagged ‘type forwarding

Коротко про type forwarding

15 комментариев

Представьте, что у вас есть 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 делать из «реальных» сборок прокси с пустышками вместо методов. ▪

Written by Dmitri

6 апреля 2011 at 14:33

Опубликовано в .NET

Tagged with