使用AutoFac 2避免服务定位器

5

我正在构建一个应用程序,使用 AutoFac 2 进行依赖注入。 我已经阅读过资料,了解到应该避免使用静态 IoCHelper (服务定位器)。

IoCHelper.cs

public static class IoCHelper
{
    private static AutofacDependencyResolver _resolver;

    public static void InitializeWith(AutofacDependencyResolver resolver)
    {
        _resolver = resolver;
    }

    public static T Resolve<T>()
    {
        return _resolver.Resolve<T>();
    }
}

之前的问题的答案中,我找到了一种通过使用自动生成工厂来帮助减少在我的UnitOfWork中使用IoCHelper的方法。继续沿着这条路走,我想知道是否可以完全消除我的IoCHelper。
以下是场景:
我有一个静态的Settings类,它作为我的配置实现的包装器。由于Settings类是大多数其他类的依赖项,该包装器使我不必在整个应用程序中注入设置类。

Settings.cs

public static class Settings
{
    public static IAppSettings AppSettings
    {
        get
        {
            return IoCHelper.Resolve<IAppSettings>();
        }
    }
}

public interface IAppSettings
{
    string Setting1 { get; }
    string Setting2 { get; }
}

public class AppSettings : IAppSettings
{
    public string Setting1
    {
        get
        {
            return GetSettings().AppSettings["setting1"];
        }
    }

    public string Setting2
    {
        get
        {
            return GetSettings().AppSettings["setting2"];
        }
    }

    protected static IConfigurationSettings GetSettings()
    {
        return IoCHelper.Resolve<IConfigurationSettings>();
    }
}

有没有一种方法可以在不使用服务定位器的情况下处理这个问题,而且不必将AppSettings注入到每个类中?以下是我在三个方面上依赖ServiceLocator而不是构造函数注入的原因:

  • AppSettings
  • 日志记录
  • 缓存
1个回答

4
我更喜欢将注入到需要它的每个类中,以使它们不受的隐藏依赖影响。问题是,你真的需要在每个类中都加入这种依赖吗?
如果您确实想使用静态的类,我建议至少尝试使其易于测试/可伪造。考虑以下内容:
public static class Settings
{
    public static Func<IAppSettings> AppSettings { get; set; }
}

你需要确定容器的构建位置:

var builder = new ContainerBuilder();
...
var container = builder.Build();

Settings.AppSettings = () => container.Resolve<IAppSettings>();

这将允许在测试期间使用伪造对象进行交换:
Settings.AppSettings = () => new Mock<IAppSettings>().Object;

现在,AppSettings 类(我假设只有一个)可以使用常规构造函数注入。我还假设您确实希望在每次调用设置属性时进行解析,因此注入一个检索所需实例的工厂委托。如果不需要这样做,当然可以直接注入 IConfigurationSettings 服务。

public class AppSettings : IAppSettings
{
    private readonly Func<IConfigurationSettings> _configurationSettings;

    public AppSettings(Func<IConfigurationSettings> configurationSettings)
    {
        _configurationSettings = configurationSettings;
    }

    public string Setting1
    {
        get
        {
            return _configurationSettings().AppSettings["setting1"];
        }
    }

    public string Setting2
    {
        get
        {
            return _configurationSettings().AppSettings["setting2"];
        }
    }
}

这是一个很好的观点。说实话,我可能不需要将这些依赖注入到每个类中,但对于同一依赖项被注入到大量类的情况,我只是想知道是否有一些最佳的 DI 实践方法。 - Page
1
看看我的更新答案。说实话,我曾经被迫这样做过一次:当无法使用构造函数注入时(设计师需要一个无参数的构造函数)。 - Peter Lillevold

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接