Как можно внедрить внедрение зависимостей в язык? [закрыто]

10

Я немного подумал о том, как лучше внедрить внедрение зависимостей непосредственно в язык C #. Я нашел потенциальное решение, о котором я хотел бы услышать ваше мнение. Я не использовал много фреймворков для внедрения зависимостей, поэтому, возможно, я что-то упускаю

В любом случае, идея состоит в том, чтобы иметь возможность объявлять свойства как «инъецируемые», используя ключевое слово. Когда объект создается, и это свойство не инициализируется с помощью конструктора или инициализатора объекта, он запрашивает экземпляр этого типа свойства у некоторой глобальной службы.

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

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

Опять же, это проблема только для классов, которые часто создаются в высокопроизводительном решении, поэтому это не должно быть проблемой. Возможно, вы могли бы использовать какую-то фабрику в этих случаях.

Мысли, проблемы, вопросы, лучшие идеи?

Код

public class SomeClass
{

  public SomeClass()
  {
     //implicit behavior if Animal is not set in constructor or initializer
    this.Animal =  GlobalInjector.Get(this,typeof(Mammal))

  }

  public injectable Mammal Animal  
  {
   get;
   set;
  }
}


 GlobalInjector.Register(typeof(Mammal), () => return new Mammal(someParameter));
Homde
источник
Не могли бы вы привести пример псевдокода для тех из нас, кто не знаком с DI? PS. Может быть, вы также можете ответить на мой вопрос относительно DI? :)
Стивен
2
Я не уверен, что понял. Вы можете получить все это с помощью глобального контейнера DI и атрибута [Injectable] вместо ключевого слова, верно?
nikie
Привет, я попытался написать немного о DI на ваш вопрос, но не уверен, что он на него отвечает
Homde
nikie: Да, конечно, я думаю, вы могли бы реализовать фактический механизм по-разному, мне больше интересно, если основная логика является здравым
Homde
Так чем же отличается этот существующий IoC от вашего дополнительного ключевого слова?
Мэтью Уайтед

Ответы:

7

Есть вещи, которые принадлежат языкам, и вещи, которых нет. Давным-давно C признал, что IO не принадлежит языку, поскольку он является внешним по отношению к вычислительной модели и может быть реализован с помощью библиотек функций.

Инъекция зависимостей такая. Он является внешним по отношению к языку и может быть реализован с помощью соответствующих структур.

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

Дядя Боб.
источник
Я согласен в теории, у вас не может быть языка, в котором каждая функция является особенностью языка без ее раздутости. Однако всегда есть место для новых более высоких абстракций, которые помогают нам писать лучший код. Возможно, внедрение зависимостей само по себе - это не проблема, которая требует решения, а проблема, которую она решает, а именно способ облегчить нам уменьшение зависимостей. Это, возможно, не лучший способ сделать это, хотя :)
Homde
5

Не нужен

Одна из вещей, которые мне больше всего нравятся в лучших DI-средах, которые я использовал, это то, что код конфигурации верхнего уровня - единственная часть вашего кода, которую нужно знать о DI. Автоматическое подключение выполняется на уровне контейнера и конфигурации / «загрузки модуля», и код вашего приложения может быть полностью не замечен.

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

С таким дизайном вам вообще не нужно менять язык для поддержки Dependency Injection.

Это потенциально опасно

Больше всего я боюсь в интегрированной с языком системе внедрения зависимостей, что она создаст барьер для любой другой реализации, но в некотором аспекте, вероятно, загорится в угол.

Некоторые способы, которыми это могло нарисовать себя в углу:

  • Только поддержка конфигурации на основе XML или только конфигурация на основе кода
  • Неспособность поддерживать шаблон проектирования Factory (не только временные компоненты: компоненты, созданные во время выполнения)
  • Каким-то образом изменив свой код, поэтому я был вынужден использовать внедрение зависимостей и не мог просто создать экземпляр своего класса для модульных тестов
  • Не поддерживает пользовательские жизненные циклы
  • Не расширяемый
  • Не подлежит замене в тех случаях, когда мне нужно больше настроек
  • Быть сломанным каким-то образом, который мы еще не понимаем, потому что мы. Net пользователи не использовали DI достаточно долго, чтобы понять подводные камни
Мерлин Морган-Грэм
источник
4

Вы видели среду управляемой расширяемости, которая поставляется с .NET 4? Вот статья, которую я написал с некоторыми примерами. По сути, это форма внедрения зависимостей, встроенная в .NET, с дополнительными функциями обнаружения во время выполнения.

Инъекции собственности выглядят так:

class Program
{
    [Import]
    public IMessageSender MessageSender { get; set; }
}

Инъекции конструктора выглядят так:

class Program
{
    [ImportingConstructor]
    public Program(IMessageSender messageSender) 
    {
    ...
    }
}

Вы можете импортировать поля, выполнять необязательный импорт, импортировать наборы сервисов, в том числе выполнять ленивый импорт с метаданными, чтобы вы могли искать подходящий сервис для создания экземпляров. Вы можете даже повторно импортировать во время выполнения, чтобы искать новые расширения.

Скотт Уитлок
источник
Хотя MEF действительно хорош для плагинов, я не думаю, что я хотел бы использовать его в качестве общего механизма DI
Homde
1
@ MKO - Можете ли вы рассказать, чего не хватает? Мне известны все статьи, в которых Гленн Блок мчится, чтобы убедить людей в том, что MEF не собирается заменять все структуры DI, но если вы посмотрите на детали, очевидно, что это скорее политическое заявление, чем что-либо еще. Однако, если вы можете дать хороший список функций, которые отсутствуют в MEF по сравнению с другими структурами DI, это поможет людям принять обоснованное решение. Кроме того, вопрос касается DI-фреймворков в C #, а MEF - это, очевидно, DI-контейнер в .NET-фреймворке.
Скотт Уитлок
2
  1. Вы на самом деле не описываете механизм конфигурации, который ИМХО является хитрым. Как заставить весь код, выполняющийся в одном потоке, использовать соединение с БД A, и весь код в соединении B другого потока? Как вы блокируете внедрение определенного ресурса, потому что пользователь, вошедший в систему, не имеет доступа к нему?
  2. Не используйте глобальный инжектор. Не используйте глобальные переменные вообще, иначе вы можете использовать глобальные переменные. Нет, использование OOP-говорящих, таких как singleton или static, вместо global не меняет их глобальную природу.
  3. Рассмотрим динамически ограниченный контейнер. Хотя лексическая область действия по праву выиграла у динамической области действия, я считаю, что динамическая область видимости станет прекрасной заменой глобальной области видимости. Дифференциальное наследование было бы хорошей реализацией (как в наследовании на основе прототипов).
  4. Я считаю, что обязательный для языка DI-механизм должен быть действительно простым, ни одна из тех корпоративных вещей, которые не являются нормой в C # и Java. Механизм динамического определения области действия с простым слоем конфигурации на вершине мог бы добиться цели. Корпоративные решения могут быть наслоены сверху третьими сторонами.
Waquo
источник