DI-Container:如何将配置传递给对象

发布于 2024-08-22 08:59:40 字数 1347 浏览 3 评论 0原文

有时我的课程需要获取一些构建信息。我不是在谈论对其他对象(将被注入)的引用,而是在谈论(例如)包含唯一信息的字符串:

// Scoped as singleton!
class Repository
{
    public Repository( InjectedObject injectedObject, string path ) { ... }
}

如何注入该字符串?一种可能性是编写一个 Init() 方法并避免注入字符串:

class Repository
{
    public Repository( InjectedObject injectedObject ) { ... }
    public void Init( string path ) { ... }
}

另一种可能性是将信息包装到一个可以注入的对象中:

class InjectedRepositoryPath
{
    public InjectedRepositoryPath( string path ) { ... }
    public string Path { get; private set; }
}

class Repository
{
    public Repository( InjectedObject injectedObject, InjectedRepositoryPath path ) { ... }
}

这样我就必须创建一个在我的 DI-Container 初始化期间创建 InjectedRepositoryPath 实例并注册该实例。但我需要为每个类似的类提供这样一个独特的配置对象。

当然,我可以解析 RepositryFactory 而不是 Repository 对象,因此工厂会询问我路径:

class RepositoryFactory
{
    Repository Create( string path ) { ... }
}

但同样,这是一个仅用于单例对象的工厂。 ..
或者,最后,由于将从配置文件中提取路径,因此我可以跳过传递字符串并在构造函数中读取配置(这可能不是最佳的,但可能):

class Repository
{
    public Repository( InjectedObject injectedObject )
    {
        // Read the path from app's config
    }
}

您最喜欢的方法是什么?对于非单例类,您必须使用 Init() 或工厂解决方案,但是单例范围的对象呢?

Sometimes I have classes which need to get some information for construction. I am not talking about references to other objects (which will be injected) but about (for instance) strings which are holding unique information:

// Scoped as singleton!
class Repository
{
    public Repository( InjectedObject injectedObject, string path ) { ... }
}

How do you get this string injected? One possiblity is to write an Init() method and to avoid injection for the string:

class Repository
{
    public Repository( InjectedObject injectedObject ) { ... }
    public void Init( string path ) { ... }
}

Another possibility is to wrap the information into an object, which can be injected:

class InjectedRepositoryPath
{
    public InjectedRepositoryPath( string path ) { ... }
    public string Path { get; private set; }
}

class Repository
{
    public Repository( InjectedObject injectedObject, InjectedRepositoryPath path ) { ... }
}

This way I'd have to create an instance of InjectedRepositoryPath during the initialisation of my DI-Container and register this instance. But I need such an unique configuration object for every similar class.

Of course I can resolve a RepositryFactory instead of the Repository object, so the factory would ask me for the path:

class RepositoryFactory
{
    Repository Create( string path ) { ... }
}

But again, this is one factory just for a singleton object ...
Or, finally, since the path will be extracted from a configuration file, I could skip passing around the string and read the config in my constructor (which is probably not as optimal, but possible):

class Repository
{
    public Repository( InjectedObject injectedObject )
    {
        // Read the path from app's config
    }
}

What's your favorite method? For non-singleton classes you have to use imho the Init() or factory solution, but what about singleton-scoped objects?

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

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

发布评论

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

评论(2

乖乖兔^ω^ 2024-08-29 08:59:40

如果您使用构造函数注入,我发现向构造函数添加一个作为配置对象的参数是最好的方法。通过使用 init 函数,您在某种程度上回避了构造函数注入的问题。这使得测试更加困难,也使得维护和交付更加困难。

发现成为一个问题,因为此类需要配置对象并不明显。通过将其添加到构造函数中,任何使用该对象的人都明确知道该配置必须存在。

If you are using Constructor injection I find adding a parameter which is your configuration object to the constructor is the best way. By using an init function you are somewhat sidestepping the point of constructor injection. This makes testing harder, it also makes maintenance and delivery more difficult.

Discovery becomes a problem because it is not readily apparent that this class requires a configuration object. By adding it to the constructor anyone using this object knows explicitly that this configuration must be there.

拒绝两难 2024-08-29 08:59:40

我不喜欢让 DI 容器决定我的 API 设计。容器应符合正确的设计,而不是相反。

DI友好的方式设计你的类,但不要做出让步到您的 DI 容器。如果您需要连接字符串,请通过构造函数获取字符串:

public class Repository : IRepository
{
    public Repository(string path) { //... }
}

许多 DI 容器可以处理原始值。作为一个例子,这是使用 Windsor 的一种方法:

container.Register(Component.For<IRepository>()
    .ImplementedBy<Repository>()
    .DependsOn( new { path = "myPath" } ));

但是,如果您选择的容器无法处理原始参数,您始终可以使用知道如何查找字符串的实现来装饰 Repository

public class ConfiguredRepository : IRepository
{
    private readonly Repository decoratedRepository;

    public ConfiguredRepository()
    {
        string path = // get the path from config, or whereever appropriate
        this.decoratedRepository = new Repository(path);
    }

    // Implement the rest of IRepository by
    // delegating to this.decoratedRepository
}

现在您可以简单地告诉容器将 IRepository 映射到 ConfiguredRepository,同时仍然保持核心存储库实现的干净。

I prefer not having a DI Container dictate my API design. The container should conform to proper design, not the other way around.

Design your classes in a DI-friendly manner, but without making concessions to your DI Container. If you need a connection string, then take a string through the constructor:

public class Repository : IRepository
{
    public Repository(string path) { //... }
}

Many DI Containers can deal with primitive values. As an example, here's one way to do it with Windsor:

container.Register(Component.For<IRepository>()
    .ImplementedBy<Repository>()
    .DependsOn( new { path = "myPath" } ));

However, if your container of choice can't deal with primitive parameters, you can always decorate Repository with an implementation that knows how to find the string:

public class ConfiguredRepository : IRepository
{
    private readonly Repository decoratedRepository;

    public ConfiguredRepository()
    {
        string path = // get the path from config, or whereever appropriate
        this.decoratedRepository = new Repository(path);
    }

    // Implement the rest of IRepository by
    // delegating to this.decoratedRepository
}

Now you can simply tell your container to map IRepository to ConfiguredRepository, while still keeping the core Repository implementation clean.

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