Реализация интерфейса без создания реализации (динамические прокси?) - PullRequest
2 голосов
/ 05 июля 2010

Я работаю над созданием собственного контейнера IoC для учебных целей.Задав пару вопросов о них, мне показали, что создание фабрики для «разрешения» объектов было лучшим решением ( см. Третье решение здесь ).Пользователь Krzysztof Koźmic показал, что Castle Windsor действительно может реализовать это для вас.

Я читал источник CW все утро.Я знаю, когда вызывается Resolve, он «возвращает интерфейс».Как этот интерфейс "перехватывает" вызовы (поскольку за ними нет реализации) и вызывает его собственные методы?

Я знаю, что здесь происходит какая-то хитрость с отражением, и это довольно удивительно.Я просто не совсем пользователь, как делается «перехват».Я попытался отважиться на кроличью нору на мерзавце, но я заблудился.Если бы кто-нибудь мог указать мне правильное направление, это было бы очень ценно.

Также - Разве создание типизированной фабрики не будет зависеть от контейнера внутри вызывающего кода?В терминах ASP.NET MVC это то, что мне кажется.

РЕДАКТИРОВАТЬ: Найдено Reflection.Emit ... это может быть то, что используется?

EDIT2: Чем больше и больше я смотрю на это, тем сложнее это звучитавтоматически создавать фабрики.Я мог бы в конечном итоге просто придерживаться повторяющегося кода.

Ответы [ 3 ]

7 голосов
/ 05 июля 2010

Здесь есть две отдельные концепции:

  1. Внедрение зависимостей просто создает экземпляр существующего класса, который реализует интерфейс.Например, у вас может быть класс MyServices, который реализует IMyServices.Платформы IoC предоставляют различные способы указать, что при запросе IMyServices он будет преобразован в экземпляр MyServices.Может быть, происходит какое-то волшебство IL Emit для настройки фабричных или вспомогательных методов, но фактические экземпляры - это просто определенные вами классы.

  2. Пересмешка позволяетсоздать экземпляр класса, который реализует интерфейс, без необходимости кодировать этот класс.Как правило, для этого обычно используются Reflection и IL Emit, как вы и думали.Обычно выдаваемый код IL довольно прост, делегируя основную часть работы методам, написанным на C #.Большая часть сложности насмешек связана с указанием поведения самого метода, так как платформы часто позволяют задавать поведение с использованием свободного синтаксиса.Некоторые, такие как Moles , просто позволяют вам указать делегата для реализации метода, хотя Moles может делать другие, более безумные вещи, такие как перенаправление вызовов на статические методы.


Чтобы уточнить немного, на самом деле вам не нужно использовать IL для реализации функциональности IoC, но это часто полезно, чтобы избежать накладных расходов на повторные вызовы Reflection, поскольку Reflection относительно дорог. Здесь - некоторая информация о том, что делает Castle Windsor.


Чтобы ответить на ваш вопрос, самое полезное место, которое я нашел для начала, это класс OpCodes .Это хорошее резюме доступных функций в IL и как функционируют OpCodes.По сути, это язык ассемблера на основе стека (не нужно беспокоиться о регистрах), но он строго типизирован и имеет первоклассный доступ к символам и понятиям объектов, таким как типы, поля и методы. Здесь является хорошей статьей Code Project, знакомящей с основами IL.Если вам интересно, я также могу отправить вам несколько вспомогательных классов, которые я создал за последние несколько лет, которые я использую для собственного кода Emit.

5 голосов
/ 06 июля 2010

Типизированная фабрика реализована с использованием библиотеки Castle DynamicProxy. Он на лету генерирует тип, который реализует интерфейс и перенаправляет все вызовы этого типа, которые вы делаете через интерфейс, на перехватчик.

Это не накладывает никакой зависимости в вашем коде. Интерфейс создается в вашей сборке, которой вы управляете, где вы не ссылаетесь на Виндзор. В другой сборке (точка входа в приложение) вы говорите Windsor об этом интерфейсе и говорите ему сделать его заводским, а Windsor узнает о вашем интерфейсе и работает с ним. Это Инверсия Контроля во всей своей красе.

Это на самом деле не так уж сложно:)

1 голос
/ 14 марта 2011

ImpromptuInterface создает динамические прокси-серверы DLR на основе интерфейсов. Это позволяет вам иметь динамическую реализацию со статическим интерфейсом. На самом деле он даже имеет базовый класс ImpromptuFactory, который обеспечивает отправную точку для создания фабрик с динамической реализацией на основе интерфейса.

...