注册原始论点构造一个类型? [英] Register a type with primitive-arguments constructor?

查看:180
本文介绍了注册原始论点构造一个类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有了在其构造一些原始类型的参数,如弦等一类。

I have a class that has in its constructor some primitive type arguments, such as string etc.

我应该如何注册统一的容器类型?

How should I register the type with unity container?

public LoginManager(
  IRegionManager regionManager, 
  IEventAggregator eventAggregator, 
  string mainRegionName, 
  Uri login, 
  Uri target)
  {
    this.regionManager = regionManager;
    this.eventAggregator = eventAggregator;
    this.mainRegionName = mainRegionName;
    this.login = login;
    this.target = target;
  }
}



更新

Remeber的 IRegionManager IEventAggregator 已知类型的棱镜UnityBootstrapper这是容器包装在我的情况。我必须重新注册它们?我想保持类型注册尽可能简单。

Update:
Remeber that the IRegionManager and the IEventAggregator are known types to the Prism UnityBootstrapper which is the container wrapper in my case. Do I have to re-register them?? I want to keep the type-registration as simple as possible.

这会被认为是一个坏习惯?没有更好的方法?

Would this be considered a bad habit? Any better alternatives?

推荐答案

说实话,我会试图阻止有一流的设计具有原始的或难以解决类型的构造函数。正如你已经从塔瓦雷斯的回答看出,你的配置变得很脆(更新:塔瓦雷斯似乎也带走了他的答案是,我不清楚原因的)。你失去编译时的支持,每一个变化到构造会让你改变你的DI配置。

To be honest, I would try to prevent to have a class design that has primitive or hard to resolve types in the constructor. As you have already seen from Tavares' answer, you're configuration gets very brittle (update: Tavares seems to have removed his answer for reasons that are not clear to me). You loose compile time support, and every change to that constructor would make you change your DI configuration.

有多种方法来改变你的设计,以防止这一点。哪一个是适用于你的是你的,但这里有一些想法:

There are multiple ways to change your design to prevent this. Which one is applicable for you is up to you, but here are a few ideas:

方法1:使用配置类:

// Defined on same level as the LoginManager
public interface ILoginManagerConfiguration
{
    Uri Login { get; }
    Uri Target { get; }
    string MainRegionName { get; }
}

// Defined closed to the composition root
private sealed class LoginManagerConfiguration
    : ILoginManagerConfiguration
{
    public Uri Login { get; set; }
    public Uri Target { get; set; }
    public string MainRegionName { get; set; }
}

现在你可以让你的 LoginManager 采取的依赖关系 ILoginManagerConfiguration

Now you can let your LoginManager take a dependency on ILoginManagerConfiguration:

public LoginManager(IRegionManager regionManager,
    IEventAggregator eventAggregator,
    ILoginManagerConfiguration configuration)
{
    ...
}



LoginManagerConfiguration 可以简单地注册的是这样的:

The LoginManagerConfiguration can simply be registered like this:

container.RegisterInstance<ILoginManagerConfiguration>(
    new LoginManagerConfiguration
    {
        Login = new Uri("Login"),
        Target = new Uri("Target"),
        MainRegionName =
            ConfigurationManager.AppSettings["MainRegion"],
    });

您也可以注入特定应用的配置界面,而不是这种类型的特定接口。我用我的项目之一使用此的应用程序配置界面的现在,但也有关于这几个重要的缺点。首先,它限制了重用另一项目的组件的可能性,因为它依赖于应用特定配置。在大多数情况下,这不会是一个问题,但还是不错的牢记。更重要的是,它poluted我的单元测试用假的配置类和代码验证正确的配置属性是否被称为

You could also inject an application specific configuration interface instead of this type specific interface. I used to use this application configuration interface currently in one of my projects, but there are a few important drawback about this. First of all it limits the possibility to reuse a component in another project, because it depends on the application specific configuration. In most cases this would not be an issue, but still good to keep in mind. More importantly, it poluted my unit tests with fake configuration classes and code to validate whether the right configuration property was called.

方法2:从类派生

另一种选择是从类派生,只为DI配置的目的。当你不能改变类签名,或者这是特别有用当类有多个构造函数重载:

Another option is to derive from that class, just for the purpose of DI configuration. This is especially useful when you can't change the class signature, or when that class has multiple constructor overloads:

private sealed class DILoginManager : LoginManager
{
    DILoginManager(IRegionManager regionManager,
        IEventAggregator eventAggregator)
        : base(regionManager, eventAggregator,
            ConfigurationManager.AppSettings["MainRegion"],
            new Uri("Login"),
            new Uri("Target"))
    {
        ...
    }
}

定义这个类接近你的应用程序的组成根源。该类成为您的DI配置的实现细节。你的类型的注册现在是非常简单的:

Define this class close to the composition root of your application. This class becomes an implementation detail of your DI configuration. Registration of your type will now be very simple:

container.RegisterType<ILoginManager, DILoginManager>();

方法3:使用一个工厂委托

我想提出的最后一个选项是一个工厂。这看起来很像Traveses的回答,但更类型安全的:

The last option I would like to present is a factory. This will look much like Traveses' answer, but is more type-safe:

container.Register<ILoginManager>(new InjectionFactory(c =>
{
    return new LoginManager(
        c.Resolve<IRegionManager>(),
        c.Resolve<IEventAggregator>(),
        ConfigurationManager.AppSettings["MainRegion"],
        new Uri("Login"),
        new Uri("Target"));
}));

这仍然是脆弱的,因为每次你改变的构造函数的 LoginManager ,你将不得不更改此配置,所以我个人比较喜欢的配置如下:

This would still be brittle, because every time you change the constructor of the LoginManager you will have to change this configuration, so I personally prefer the following configuration:

container.Register<ILoginManager>(new InjectionFactory(c =>
{
    // allow the container to auto-wire the instance.
    var manager = c.Resolve<LoginManager>();

    manager.Login = new Uri("Login");
    manager.Target = new Uri("Target");
    manager.MainRegionName =
        ConfigurationManager.AppSettings["MainRegion"];

    return manager;
}));



对于这个工作,你需要(再次)删除字符串乌里从构造参数和它们定义为在 LoginManager 公共属性:

For this to work, you need to (again) remove the string and Uri arguments from the constructor and define them as public properties on the LoginManager:

public LoginManager(IRegionManager regionManager,
    IEventAggregator eventAggregator)
{
    ...
}

public Uri Login { get; set; }
public Uri Target { get; set; }
public string MainRegionName { get; set; }

请注意,这些属性可能实现细节,所以你不希望有他们在这最后的办法 ILoginManager 接口。

Note that these properties are probably implementation details, so you don't want to have them on the ILoginManager interface.

缺点是,它并没有明确传达登录目标,是必需的, MainRegionName 。属性通常是可选的。如果选择这种方式,您可能希望让 Loginmanager 验证其状态,做任何事情之前有用。它应该抛出一个出现InvalidOperationException 时,不设置的属性之一。

Downside of this last approach is that it doesn't communicate clearly that Login, Target, and MainRegionName are required. Properties are usually optional. If you choose this approach, you might want to let the Loginmanager validate its state, before doing anything useful. It should throw an InvalidOperationException when one of the properties are not set.

我希望这有助于。

这篇关于注册原始论点构造一个类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆