Как да комбинирате проектируеми компоненти с инжектиране на зависимости

Когато създавате проектируем .NET компонент, от вас се изисква да предоставите конструктор по подразбиране. От документацията на IComponent:

За да бъде компонент, класът трябва да имплементира интерфейса IComponent и да предостави основен конструктор, който не изисква параметри или един параметър от тип IContainer.

Това прави невъзможно инжектирането на зависимости чрез аргументи на конструктора. (Могат да бъдат предоставени допълнителни конструктори, но дизайнерът ще ги игнорира.) Някои алтернативи, които обмисляме:

  • Намиране на услуги

    Не използвайте инжектиране на зависимости, вместо това използвайте модела за локатор на услуги, за да придобиете зависимости. Изглежда това е IComponent.Site.GetService за. Предполагам, че можем да създадем имплементация на ISite за многократна употреба (ConfigurableServiceLocator?), която може да бъде конфигурирана с необходимите зависимости. Но как работи това в дизайнерски контекст?

  • Инжектиране на зависимост чрез свойства

    Инжектирайте зависимости чрез свойства. Осигурете екземпляри по подразбиране, ако са необходими за показване на компонента в дизайнер. Документирайте кои свойства трябва да бъдат инжектирани.

  • Инжектиране на зависимости с метод за инициализиране

    Това много прилича на инжектиране чрез свойства, но поддържа списъка със зависимости, които трябва да бъдат инжектирани на едно място. По този начин списъкът с необходимите зависимости е документиран имплицитно и компилаторът ще ви помогне с грешки, когато списъкът се промени.

Имате ли идея коя е най-добрата практика тук? Как го правиш?


редактиране: Премахнах „(напр. WinForms UserControl)“, тъй като възнамерявах въпросът да бъде относно компонентите като цяло. Всички компоненти са свързани с инверсия на контрола (вижте раздел 8.3.1 от UMLv2 спецификация), така че не мисля, че „не трябва да инжектирате никакви услуги“ е добър отговор.


редактиране 2: Отне малко игра с WPF и модела MVVM, за да „получим“ най-накрая отговора на Марк. Сега виждам, че визуалният контрол наистина е специален случай. Що се отнася до използването на невизуални компоненти върху дизайнерски повърхности, мисля, че моделът на .NET компонент е фундаментално несъвместим с инжектирането на зависимости. Изглежда, че вместо това е проектиран около модела на локатора на услугата. Може би това ще започне да се променя с инфраструктурата, която беше добавена в .NET 4.0 в System.ComponentModel.Composition пространство от имена.


person Wim Coenen    schedule 30.06.2009    source източник


Отговори (1)


Същият въпрос ме измъчваше дълго време, докато не осъзнах, че мисля за него по грешен начин. AFAIR, единствената причина за създаване на реализация на IComponent е да се осигурят функции по време на проектиране - няма ефект на изпълнение на имплементации на IComponent.

Като следствие, това означава, че най-вече трябва да създавате компоненти за внедряване на функции по време на проектиране. Особено за контролите това означава, че можете да конфигурирате компонента да се държи по определен начин. Много е важно да разберете, че това е съвсем различна грижа от това как компонентът всъщност се държи или какви данни показва. Не трябва да има поведение по време на проектиране и не трябва да съдържа данни.

Като такова, ограничението върху конструктора всъщност е благословия, тъй като ви инструктира да преосмислите своя дизайн. Контролът е агностичен софтуер за източник на данни, който показва и взаимодейства с данните по определен начин. Докато тези данни съответстват на определени интерфейси и т.н., контролът е щастлив. Как пристигат тези данни не е от значение за Контрола и не трябва да бъде. Би било грешка да позволите на Control да контролира как се зареждат и модифицират данните.

В WPF това е изрично много по-ясно, отколкото в Windows Forms: Вие давате на конкретен контрол DataContext и свързвате свойствата на контролата към членовете на този DataContext. DataContext (който може да бъде всеки обект) произхожда извън контрола; това е отговорността или вашият слой за представяне.

В Windows Forms все още можете да направите същото, като присвоите контекст на данни на контрола. По същество това е инжектиране на собственост - просто имайте предвид, че не трябва да инжектирате услуги; трябва да инжектирате данни.

В обобщение, не бих се съгласил с нито едно от вашите предложения. Вместо това оставете контролата да има едно или повече свойства, които ви позволяват да присвоявате данни на контролата и да използвате обвързване на данни, за да се свържете с тези данни. Вътре в изпълнението на контролата, бъдете готови да се справите със ситуацията, в която няма данни: Това ще се случва всеки път, когато контролата се хоства от VS по време на проектиране. Моделът Null Object е много полезен за прилагане на такава устойчивост.

След това настройте контекста на данните от вашите контролери. Това е начинът на MVC да го направи: Контролът е изгледът, но трябва да имате отделен контролер, който може да създаде и присвои модел на изгледа.

person Mark Seemann    schedule 02.07.2009
comment
Ако тълкувам отговора ви правилно, вие казвате, че контролите не трябва да използват никакви услуги. Не съм сигурен дали съм съгласен. Например, имам контрола, която не изобразява текст директно чрез извикване на System.Windows.Forms.TextRenderer. Вместо това той използва инжектируема услуга ITextRenderer (с основно същите методи). Това ми позволява да внедрявам фантастични стратегии за съкращения отвъд предоставеното от .NET framework, като същевременно поддържам такъв код независим от самата контрола. - person Wim Coenen; 03.07.2009
comment
Да, казвам, че контролите не трябва да използват услуги - услугите трябва да използват контроли. Контролата не трябва да прави нищо, освен да изобразява потребителския интерфейс. Добре е, че можете да инжектирате фантастични стратегии за съкращения, но тази логика принадлежи на (View) модела, а не на самия изглед. След това можете да обвържете данните си с изглед към свойства на модела, които произвеждат желаните стойности, като извикате инжектираните зависимости. Въпреки че изглежда, че използвате WinForms, вижте това за вдъхновение: msdn.microsoft .com/en-us/magazine/dd419663.aspx - person Mark Seemann; 04.07.2009