代码之家  ›  专栏  ›  技术社区  ›  TheCodeKing

带参数的联合汽车厂

  •  16
  • TheCodeKing  · 技术社区  · 14 年前

    public class TestLog
    {
         private Func<ILog> logFactory;
    
         public TestLog(Func<ILog> logFactory)
         {
              this.logFactory = logFactory;
         }
         public ILog CreateLog()
         {
             return logFactory();
         }
    }
    
    Container.RegisterType<ILog, Log>();
    TestLog test = Container.Resolve<TestLog>();
    ILog log = test.CreateLog();
    

    现在我想做的是:

    public class TestLog
    {
         private Func<string, ILog> logFactory;
    
         public TestLog(Func<string, ILog> logFactory)
         {
              this.logFactory = logFactory;
         }
         public ILog CreateLog(string name)
         {
             return logFactory(name);
         }
    }
    
    Container.RegisterType<ILog, Log>();
    TestLog test = Container.Resolve<TestLog>();
    ILog log = test.CreateLog("Test Name");
    

    不幸的是,这不起作用。我可以看到您如何设置自定义工厂来创建Unity中的实例,只是似乎无法为这个示例提供任何清晰的示例。

    我可以创建我自己的工厂,但我正在寻找一个优雅的方式来做到这一点,在统一和最少的代码。

    4 回复  |  直到 9 年前
        1
  •  33
  •   TheCodeKing    14 年前

    public class TestLog
    {
        private Func<string, ILog> logFactory;
    
        public TestLog(Func<string, ILog> logFactory)
        {
             this.logFactory = logFactory;
        }
        public ILog CreateLog(string name)
        {
            return logFactory(name);
        }
    }
    
    Container.RegisterType<Func<string, ILog>>(
         new InjectionFactory(c => 
            new Func<string, ILog>(name => new Log(name))
         ));
    
    TestLog test = Container.Resolve<TestLog>();
    ILog log = test.CreateLog("Test Name");
    
        2
  •  7
  •   TheBigB    8 年前

    @TheCodeKing的答案很好,但在大多数情况下(可能是全部?)案例可缩短为:

    Container.RegisterInstance<Func<string, ILog>>(name => new Log(name));
    

    (请注意,我正在使用 RegisterInstance() 而不是 RegisterType()

    自从 Func<> 实现已经是一种工厂,通常不需要将它包装在 InjectionFactory . 它只确保 Func<string, ILog> 是一个新的实例,我真的想不出一个场景需要这个。

        3
  •  1
  •   Pedro Pombeiro    9 年前

    如果您正在寻找一个完全类型化的工厂接口(例如,允许XML文档和参数名),可以使用 NuGet package

    代码存在于GitHub中: https://github.com/PombeirP/FactoryGenerator

        4
  •  1
  •   Nik    6 年前

    Autofac parameterized instantiation

    Unity

    一个无耻的插件:我实现了这样一个扩展-- Parameterized Auto Factory .

    public class Log
    {
        public void Info(string info) { /* ... */ }
        public void Warn(string info) { /* ... */ }
        public void Error(string info) { /* ... */ }
    }
    
    public class LogConsumer
    {
        private readonly Log _log;
        private readonly string _consumerName;
    
        public LogConsumer(Log log, string consumerName)
        {
            _log = log;
            _consumerName = consumerName;
        }
    
        public void Frobnicate()
            => _log.Info($"{nameof(Frobnicate)} called on {_consumerName}");
    }
    
    var container = new UnityContainer()
        .AddNewExtension<UnityParameterizedAutoFactoryExtension>();
    
    var logConsumerFactory = container.Resolve<Func<string, LogConsumer>>();
    var gadget = logConsumerFactory("Gadget");
    gadget.Frobnicate();
    

    请注意:

    • Func<string, LogConsumer> container ,但它没有在任何地方注册--它是自动生成的。
    • Func<字符串,LogConsumer> string consumerName 参数到 LogConsumer 的构造函数。因此 Log log 参数从容器中解析。如果汽车工厂的功能是这样的 Func<string, Log, LogConsumer> 取而代之的是 的构造器应该是由汽车厂提供的。

    1. 它注册了一个所谓的 BuilderStrategy 在统一的管道里。
    2. 如果要生成的类型没有显式注册并且是 Func
    3. 现在我们只需要动态地创建一个 功能 从容器解析其返回类型并传递 功能 ResolverOverride 集合到 IUnityContainer.Resolve 方法。