Динамическое определение зависимости на основе пользовательских параметров - PullRequest
5 голосов
/ 06 февраля 2011

Проблема

В настоящее время у меня есть фабрика, которая зависит от нескольких параметров, чтобы правильно решить, какой объект вернуть.Этот завод еще не связан с DI.Насколько я понимаю, NInject использует провайдеров как фабрику.

Вот что у меня сейчас есть.Я предупреждаю вас, что это не красиво.

public interface IRole
{
    string Name { get; }
}

public class FooRole : IRole
{
    public string Name { get { return "Foo Role"; } }
}

public class BarRole : IRole
{
    public string Name { get { return "Bar Role"; } }
}

public class FooBarRoleModule : NinjectModule
{
    public override void Load()
    {
        Bind<IRole>().ToProvider<RoleProvider>();
    }
}

public class RoleProvider : Provider<IRole>
{
    protected override IRole CreateInstance(IContext context)
    {
        var isNewParameter = context.Parameters
            .Where(x => x.Name == "isNew")
            .Select(x => x.GetValue(context))
            .Cast<bool>()
            .FirstOrDefault();

        if (isNewParameter) return new FooRole();
        return new BarRole();
    }
}

var role = kernel.Get<IRole>(new ConstructorArgument("isNew", true));
Console.WriteLine(role.Name);

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

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

Вопрос

Как правильно использовать провайдера с параметрами, неизвестными при запуске?время?Эти параметры будут передаваться всякий раз, когда пользователь запускает код, который может дать им другую роль.

Спасибо.

Редактировать

public class RoleFactory : IRoleFactory
{
    public IRole Create(bool isNew)
    {
        if (isNew) return new BarRole();
        return new FooRole();
    }
}

Свяжите его с Bind<IRoleFactory>().To<RoleFactory>(); и используйте его вот так.

var role = kernel.Get<IRoleFactory>();
Console.WriteLine(role.Create(true).Name);

Эта пересмотренная версия выглядит лучше и имеет больше смысла, однако я считаю, что я пропустил некоторые ключевые детали в вашем посте.Хотелось бы добавить, что параметр isNew будет истинным, если фабрика была вызвана, например, из кнопки «Создать новое событие».

1 Ответ

6 голосов
/ 07 февраля 2011

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

Использовать именованные привязки:

kernel.Bind<IRole>().To<FooRole>().Named("old");
kernel.Bind<IRole>().To<BarRole>().Named("new");
kernel.Get<IRole>("new");

Использовать условные привязки

kernel.Bind<IRole>().To<AdminRole>().When(ctx => UserHasAdminPermission())
kernel.Bind<IRole>().To<UserRole>();
kernel.Get<IRole>();
...