Инъекция зависимостей и наследование классов - PullRequest
11 голосов
/ 25 мая 2009

Я чувствую, что это то, что я должен уже знать, но я просто не запускаю все двигатели сегодня ...

У меня есть базовый класс с одним ctor, который принимает реализацию интерфейса как единственный параметр. Я использую DI-фреймворк, и все мои регистрации компонентов настроены и работают нормально.

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

Итак, сейчас у меня есть:

public class MyObjectBase
{
    IMyRequiredInterface _InterfaceImpl;
    public MyObjectBase(IMyRequiredInterface interfaceImpl)
    {
        _InterfaceImpl = interfaceImpl;
    }
    ...
}

public class AnotherObject : MyObjectBase
{
    public AnotherObject()
    {
    }
    ...
}

Итак, из ворот это не получится. Я получаю ошибки при создании экземпляра AnotherObject, указывающего, что нет базового класса ctor, который принимает 0 параметров. Хорошо, я понял. Но теперь у меня есть выбор: либо изменить ctor класса-потомка так, чтобы он принимал аналогичный параметр, и передать это значение базовому ctor, либо подключить цепочку ctor в базовом классе, которая заставляет меня обходить DI и создавать конкретную реализацию требуемый интерфейс и передать его как часть объявления ctor без параметров.

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

Может быть, я ошибаюсь, но это меня беспокоит. Есть мысли о лучшем способе справиться с этим? Я чувствую, что мне не хватает чего-то простого ...

Ответы [ 7 ]

14 голосов
/ 25 мая 2009

Правильный подход:

public class AnotherObject : MyObjectBase {
    public AnotherObject(IMyRequiredInterface interfaceImpl) : 
        base(interfaceImpl) {
    }
}

Вы специально просили подход, отличный от этого. Почему?

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

Как правило, это неправильно. Почему ты хочешь это сделать?

Обновление:

Исходя из вашего последующего комментария, вам, вероятно, следует использовать (и настроить свой контейнер для использования) внедрение свойств вместо внедрения конструктора. Это удовлетворит все ваши требования.

4 голосов
/ 25 мая 2009

Err .... весь смысл наследования от MyObjectBase заключается в том, что вы получаете как хорошее, так и плохое в отношении поведения. Если вы не можете создать MyObjectBase без объекта, реализующего IMyRequiredInterface, вы также не можете создать подкласс без такого объекта.

Итак, что вы делаете, когда кто-то не передает вам это. У вас есть по умолчанию?

Для подкласса вполне разумно создать экземпляр того, что реализует IMyRequiredInterface, и передать это конструктору суперкласса с помощью вызова super(...). Вы можете сделать это? (Хотя, насколько я помню, вы можете немного зацикливаться на Java, вызывая super, прежде чем делать что-либо еще ....)

1 голос
/ 25 мая 2009

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

0 голосов
/ 11 августа 2016

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

Но у Autofac (я считаю, что и другие контейнерные инструменты) есть .InstancePerRequest (), который будет использовать тот же экземпляр для запроса Http.

builder.RegisterType () Как () InstancePerRequest ();..

0 голосов
/ 25 мая 2009

Большинство структур DI имеют функциональные возможности для добавления сервисов в свойства (Property Setter Injection) с использованием атрибутов, поэтому вы можете попробовать это.

Вы можете создавать подкласс, но подкласс должен знать, как создать или получить реализацию интерфейса (используя ServiceLocator или что-то еще).

С точки зрения DI, ему нечего выполнять, потому что у класса есть только пустой конструктор (большинство используют конструктор с наибольшим количеством параметров) и нет атрибутов, указывающих ему делать что-либо еще.

0 голосов
/ 25 мая 2009

Я бы сделал это:

public class AnotherObject:MyObjectBase
{
 public AnotherObject():MyObjectBase(new RequiredInterfaceImplementation())
 {
 }
}

Где:

public class RequiredInterfaceImplementation:IMyRequiredInterface
{
 ... your implementation
}
0 голосов
/ 25 мая 2009

Как насчет предоставления защищенного конструктора в базовом классе, который не принимает параметров?

    class MyBase
{
    readonly int _x;
    public MyBase(int x)
    {
        _x = x;
    }

    protected MyBase()
    {
        _x = 0;
    }
}

class MyChild : MyBase
{
    public MyChild()
    {

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...