2017-03-11 43 views
2

我在使用DryIoC时遇到了一个相当令人费解的情况。 OK,实际上,这是我第一次使用IoC容器,所以我可能会误解一切:从依赖注入到IoC容器,再到DryIoC本身。DryIoC - 在解析时指定一些构造函数参数

不过,我一直是一个专业的程序员很长一段时间,我有体面的谷歌搜索技巧,我甚至找不到类似的问题暴露其他人。

比方说,我有一个类库暴露这些接口......

namespace Logging 
{ 
    public interface ILogger 
    { 
     void Info(string message); 
    } 

    public interface ILoggerFactory 
    { 
     ILogger CreateLogger(string name); 
    } 
} 

...和其他类库实现上述接口。

namespace Logging.Console 
{ 
    internal class ConsoleLogger : ILogger 
    { 
     readonly string _name; 

     public ConsoleLogger(string name) 
     { 
      _name = name; 
     } 

     void Info(string message) => System.Console.WriteLine($"[{_name}] {message}"); 
    } 

    public class ConsoleLoggerFactory : ILoggerFactory 
    { 
     public ILogger CreateLogger(string name) => new ConsoleLogger(name); 
    } 
} 

然后用其他的东西,第三个库,我需要:

namespace LibraryA 
{ 
    public interface IServiceA 
    { 
     // bla bla 
    } 

    public class ServiceA : IServiceA 
    { 
     // Implement service A 
    } 

    public interface IServiceB 
    { 
     // yada yada 
    } 

    public class ServiceB : IServiceB 
    { 
     // Implement service B 
    } 
} 

最后,利用上述所有库类库实现一个咖啡研磨机(我爱咖啡!)

using Logging; 
using LibraryA; 

namespace Coffee 
{ 
    public interface ICoffeeGrinder 
    { 
     GrindCoffee(int grams); 
    } 

    public class CoffeeGrinder : ICoffeeGrinder 
    { 
     readonly ILogger _logger; 
     readonly IServiceA _serviceA; 
     readonly IServiceB _serviceB; 

     public CoffeeGrinder(ILoggerFactory loggerFactory, string loggerName, 
      IServiceA serviceA, IServiceB serviceB) 
     { 
      _logger = loggerFactory.CreateLogger(loggerName); 
      _serviceA = serviceA; 
      _serviceB = serviceB; 
     } 

     public GrindCoffee(int grams) 
     { 
      _logger.Info($"About to grind {grams}g of coffee..."); 
      // Grind coffee 
      _logger.Info("Done grinding."); 
     } 
    } 
} 

根据(例如)配置文件,应用程序可能需要多个研磨器,每个研磨器都有自己的名称。

因此,我希望能够在解析时指定loggerName,像这样:

using Coffee; 
using DryIoC; 
using LibraryA; 
using Logging; 
using Logging.Console; 

namespace MyApplication 
{ 
    class Program 
    { 
     static void Main() 
     { 
      using (var container = new Container()) 
      { 
       container.Register<ILoggerFactory, ConsoleLoggerFactory>(); 
       container.Register<IServiceA, ServiceA>(); 
       container.Register<IServiceB, ServiceB>(); 
       container.Register<ICoffeeGrinder, CoffeeGrinder>(
        /* Maybe some magic here? */); 

       // This won't work 
       var grinder = container.Resolve<ICoffeeGrinder>("My grinder"); 
       // Use grinder 
      } 
     } 
    } 
} 

换句话说,我怎么告诉DryIoC一个或多个构造函数的参数是依赖关系,但必须在解决时间指定?

+1

我想问你是否真的想这样做。就其性质而言,构造函数参数也是一种依赖关系,它们依赖于底层类的具体实现。你想要传入的字符串,在完全不同的服务中具有完全不同的实现语义的那个字符串的含义是什么?它应该是一个url的东西?一个文件名和路径?什么的名字?您仍然将具体的实现细节泄漏到消耗服务的代码中。在我看来,你不应该那样做。 –

+0

@ LasseV.Karlsen所讨论的字符串只是一个名称,用于标识日志中的对象。我认为这不算是泄漏的实施细节。 'CoffeeGrinder'的构造函数可以使用'ILogger',但它也应该在解析时指定,所以问题将会是相同的。 然后,再次,我可能在写这样的构造函数时首先会出现灾难性的错误。我只是没有看到任何更好的方式让我的类使用一个记录器,而这个记录器的名字不为该类所知,但是调用构造函数的代码已知它。 – rdeago

+0

我很确定是可能的,但不幸的是我今晚不在我的电脑。查看Resolve方法是否有'with'参数。 –

回答

5

解析为Func<string, ICoffeeGrinder>,这是主要容器支持的常见功能,例如, Autofac。这里是DryIoc wiki topic

var getGrinder = container.Resolve<Func<string, ICoffeeGrinder>>(); 
var grinder = getGrinder(name); 

顺便说一句,你可能会考虑很多的IoC/DI容器major feature list节省您的时间。此链接也可在DryIoc自述文件的基准下获得。

+0

非常感谢@dadhi!这正是我所期待的。当我阅读文档时,我不知道它是如何逃脱我的(因为是的,我确实读过它)。信息可能溢出。啊,我变老了...... :-) – rdeago

相关问题