При условии, что у меня есть класс следующим образом
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.
То, что вы используете заводы для:
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
которые вы вызываете. Это полностью устранит проблему.
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.