Динамический вызов Autofac с инъекцией функций и зависимостей

1

При условии, что у меня есть класс следующим образом

public class Foo
{
    public Foo(string someTitle, IFooService fooService)
    { 
        // do stuff
    }
}

Я знаю, что я могу создать его таким образом, используя DI и autofac

public class Bar
{
    public Bar(Func < string, IFooService, Foo > foo, IFooService fooService)
    {
        var foo = foo("some string", fooService);
    }
}

но мне интересно, есть ли способ, чтобы Bar не знал ничего о IFooService? Я бы не хотел вводить IFooService в Bar только для того, чтобы удовлетворить func.

По сути, что-то вроде этого

// pseudo code - don't use
public class Bar
{
    public Bar(Func < string, Foo > foo)
    {
        var foo = foo("some string");
    }
}

То, что я действительно пытаюсь сделать в своем приложении, - удалить все экземпляры Service Location и полагаться исключительно на Injection Dependency.

Теги:
dependency-injection
autofac
service-locator

2 ответа

2
Лучший ответ

То, что вы используете заводы для:

public interface IFooFactory
{
    Foo CreateFoo(string value);
}

И бар может просто зависеть от IFooFactory.

Реализация может выглядеть следующим образом:

public class FooFactory : IFooFactory
{
    private readonly IFooService fooService;

    public FooFactory(IFooService fooService)
    { 
        this.fooService = fooService;
    }

    public Foo CreateFoo(string value)
    {
        return new Foo(value, this.fooService);
    }
}

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

5

Autofac должен иметь возможность делать именно то, что вы хотите, используя неявное отношение Func<T>.

Вот небольшой репростак, показывающий, как вы можете опустить параметр IFooService в Func<T> и пока другие зависимости могут быть разрешены Autofac, вам хорошо идти.

Примеры типов, которые делают сумасшедшую работу...

public class Bar
{
    private Foo _foo;

    // This constructor looks like what you're aiming for...
    public Bar(Func<string, Foo> factory)
    {
        this._foo = factory("title");
    }

    public void ShowMeCoolStuff()
    {
        this._foo.DoWork();
    }
}

public class Foo
{
    private string _title;
    private IFooService _service;

    // The Foo class takes the title AND an IFooService...
    public Foo(string title, IFooService service)
    {
        this._title = title;
        this._service = service;
    }

    public void DoWork()
    {
        Console.WriteLine("Foo title = {0}", this._title);
        this._service.DoMoreWork();
    }
}

public interface IFooService
{
    void DoMoreWork();
}

public class FooService : IFooService
{
    public void DoMoreWork()
    {
        Console.WriteLine("FooService doing more work.");
    }
}

Когда вы регистрируетесь, убедитесь, что все зависимости зарегистрированы - Foo, Bar, что-то реализующее IFooService:

var builder = new ContainerBuilder();
builder.RegisterType<Foo>();
builder.RegisterType<Bar>();
builder.RegisterType<FooService>().As<IFooService>();
var container = builder.Build();

Когда вы разрешаете, все цепляется за линию. Это разрешение...

var bar = container.Resolve<Bar>();
bar.ShowMeCoolStuff();

... даст следующий выход консоли:

Foo title = title
FooService doing more work.

Существует довольно надежная документация с примерами на сайте Autofac.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню