【问题标题】:Autofac dynamic invocation with Func and Dependency Injection使用 Func 和依赖注入的 Autofac 动态调用
【发布时间】:2014-09-12 14:49:14
【问题描述】:

假设我有一个类如下

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。

基本上是这样的

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

我真正想要在我的应用中做的是删除所有服务位置实例,并完全依赖依赖注入。

【问题讨论】:

    标签: c# dependency-injection autofac service-locator


    【解决方案1】:

    Autofac 应该能够通过使用 the Func&lt;T&gt; implicit relationship 完成您想要的操作。

    这里有一个小例子,展示了如何在 Func&lt;T&gt; 中省略 IFooService 参数,只要 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.");
        }
    }
    

    注册时,确保所有依赖项都已注册 - FooBar、实现 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.
    

    There is fairly robust documentation with examples over on the Autofac site.

    【讨论】:

      【解决方案2】:

      这就是你使用工厂的地方:

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

      bar 可以简单地依赖于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);
          }
      }
      

      但是给定的字符串看起来像是一个运行时值,即一个在请求之间或从调用到调用时变化的值。如hereherehere 所述,防止将运行时值与设计时相关性混合。相反,将运行时值作为方法参数传递给您正在调用的 Foo 方法。这将彻底解决问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-09
        • 2018-09-25
        • 2013-12-02
        • 2018-06-16
        • 1970-01-01
        • 2017-04-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多