带参数的 Unity 自动工厂

发布于 2024-09-25 14:51:02 字数 1065 浏览 3 评论 0原文

我正在尝试找出注入带有参数的自动工厂的正确方法,或者即使这可以通过 Unity 实现。

例如,我知道我可以这样做:

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 中创建实例,但似乎无法为该示例提供任何明确的示例。

显然我可以创建自己的工厂,但我正在寻找一种优雅的方法来在 Unity 中以最少的代码实现此目的。

I'm trying to figure out the correct way to inject an auto-factory which takes params, or even if this is possible with Unity.

For example I know I can do this:

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();

Now what I'll like to be able to do is:

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");

Unfortunately this doesn't work. I can see how you can set up custom factories for creating instances in Unity, just can't seem to fund any clear examples for this example.

Obviously I could create my own factory but I'm looking for an elegant way to do this in Unity and with minimum code.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

自此以后,行同陌路 2024-10-02 14:51:02

很抱歉成为那些自己回答问题的烦人之一,但我想通了。

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");

Sorry to be one of those annoying people who answer their own questions but I figured it out.

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");
怀里藏娇 2024-10-02 14:51:02

@TheCodeKing 的答案工作正常,但在大多数(可能是所有?)情况下可以缩短为以下内容:

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

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

由于 Func<> 实现已经是一种工厂,因此通常不需要将其包装在 InjectionFactory 中。它仅确保 Func 的每个解析都是一个新实例,我真的无法想到需要此的场景。

The answer by @TheCodeKing works fine, but in most (possibly all?) cases could be shortened to the following:

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

(note that I'm using RegisterInstance() instead of RegisterType())

Since the Func<> implementation is already a kind of factory there's usually no need to wrap it in a InjectionFactory. It only ensures that each resolution of the Func<string, ILog> is a new instance, and I can't really think of a scenario that requires this.

不爱素颜 2024-10-02 14:51:02

Autofac 具有 参数化实例化来处理需要带参数的自动工厂的场景。

虽然 Unity 不支持开箱即用,但可以实现一个可以在类似于 Autofac 的方式。

一个无耻的插件:我实现了这样一个扩展——参数化汽车工厂
它的使用方式与此类似:

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 是从 container 解析的,但它没有在任何地方注册 - 它是生成的自动地。
  • Func 仅向 LogConsumer 的构造函数提供 string ConsumerName 参数。结果,Log log 参数从容器中解析出来。如果自动工厂函数看起来像这样 Func,那么 LogConsumer 构造函数的所有参数都将通过 auto 提供-工厂。

基本上,该扩展的工作原理如下:

  1. 它在 Unity 的管道中注册一个所谓的 BuilderStrategy。
  2. 每当 Unity 要构建类型的实例时,就会调用此策略。
  3. 如果要构建的类型尚未显式注册,并且是带有参数的 Func,则扩展会拦截实例构建过程。
  4. 现在,我们只需动态创建给定类型的 Func,该函数从容器解析其返回类型,并将 Func 的参数作为 ResolverOverride 集合到 IUnityContainer.Resolve 方法。

Autofac has parameterized instantiation to handle scenarios which need an auto-factory with parameters.

While Unity doesn't support this out of the box, it's possible to implement an extension which will work in a way similar to Autofac's.

A shameless plug: I implemented such an extension -- Parameterized Auto Factory.
It can be used in a way similar to this:

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();

Please notice:

  • Func<string, LogConsumer> is resolved from container, but it wasn't registered anywhere -- it's generated automatically.
  • Func<string, LogConsumer> only provides the string consumerName parameter to LogConsumer's constructor. As a result, the Log log parameter is resolved from the container. If the auto-factory func looked like this Func<string, Log, LogConsumer> instead, then all the parameters of LogConsumer's constructor would've been supplied through the auto-factory.

Basically, the extension works like this:

  1. It registers a so called BuilderStrategy in Unity's pipeline.
  2. This strategy gets invoked whenever Unity is going to build a type's instance.
  3. If the type to be built hasn't been registered explicitly and is a Func with parameters, the extension intercepts the instance building process.
  4. Now we only need to dynamically create a Funcof the given type which resolves its return type from the container and passes the Func's parameters as a ResolverOverride collection to the IUnityContainer.Resolve method.
入画浅相思 2024-10-02 14:51:02

如果您正在寻找完全类型化的工厂接口(例如,允许 XML 文档和参数名称),您可以使用 NuGet 包,您只需为工厂定义一个接口,然后将其与您想要的具体类型相关联即可利用它实例化。

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

In case you're looking for a fully typed factory interface (allowing for XML documentation and parameter names, for instance), you could use a NuGet package I created, which you can leverage simply by defining an interface for the factory, and then associating it with the concrete type you want to instantiate.

Code lives in GitHub: https://github.com/PombeirP/FactoryGenerator

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文