Мне хотелось бы получить немного больше информации, прежде чем публиковать этот ответ, но Келли поставила меня на место.:) Говоря мне, чтобы я поместил свой код, так сказать, в уста.
Как я уже сказал в своем комментарии к Келли, я не согласен с перемещением преобразователя / локатора из статической реализации в внедренную реализацию.Я согласен с ChrisChris в том, что зависимости, которые нужны производному типу, должны быть разрешены в этом классе, а не делегированы базовому классу.
Тем не менее, вот как я могу удалить расположение службы ...
Создать командный интерфейс
Прежде всего, я бы создал командный интерфейс для конкретной реализации.В этом случае типы, отправленные с помощью метода DoActions, генерируются из атрибутов, поэтому я бы создал IAttributeCommand
.Я добавляю метод Matches
к команде, чтобы объявить команду для использования определенными типами.
public interface IAttributeCommand
{
bool Matches(Type type);
void Execute();
}
Добавить реализацию команд
Чтобы реализовать интерфейс, я передаюконкретные зависимости, которые мне нужны для выполнения моей команды (разрешается моим контейнером).Я добавляю предикат в свой метод Matches и определяю свое поведение Execute.
public class MyTypeAttributeCommand : IAttributeCommand
{
MyDependency dependency;
SomeOtherDependency otherDependency;
public MyTypeAttributeCommand (MyDependency dependency, ISomeOtherDependency otherDependency)
{
this.dependency = dependency;
this.otherDependency = otherDependency
}
public bool Matches(Type type)
{
return type==typeof(MyType)
}
public void Execute()
{
// do action using dependency/dependencies
}
}
Регистрация команд с контейнером
В StructureMap (используйте ваш любимый контейнер) я бы зарегистрировал массив следующим образом:
Scan(s=>
{
s.AssembliesFromApplicationBaseDirectory();
s.AddAllTypesOf<IAttributeCommand>();
s.WithDefaultConventions();
}
Выбор и выполнение команд на основе типа
Наконец, для базового класса я определяю массив IAttributeCommand
в моих аргументах конструктора, которые будут вводиться контейнером IOC.Когда производный тип передается в массиве types
, я выполню правильную команду на основе предиката.
public abstract class MyController : Controller
{
protected IAttributeCommand[] commands;
public MyController(IAttributeCommand[] commands) { this.commands = commands); }
protected void DoActions(Type[] types)
{
foreach(var type in types)
{
var command = commands.FirstOrDefault(x=>x.Matches(type));
if (command==null) continue;
command.Execute();
}
}
}
Если несколько команд могут обрабатывать один тип, вы можете изменить реализацию: commands.Where(x=>x.Matches(type)).ToList().ForEach(Execute);
Эффект тот же, но есть небольшая разница в том, как создается класс.Этот класс не связан с контейнером IOC и не имеет служебного местоположения.Реализация более тестируема, так как класс может быть создан с его реальными зависимостями, без необходимости подключать контейнер / распознаватель.