在扩展方法中需要Factory类



我正在开发一个大型遗留C#应用程序,分配给我的任务是删除静态工厂类ServiceLocator.GetObject<T>()的所有用法,并替换为贯穿始终的构造函数注入的依赖项。

在大多数情况下,这很简单,但在应用程序代码库中大约有50种情况下这有点棘手。例如,Servicelocator用于静态类、扩展方法,甚至WPF MarkupExtension!中!。

例如,如果您遇到这样的代码片段,您会怎么做?(除了哭泣)

public static class MyExtensions
{
    private static ISingletonServiceOne _ServiceOne = null;
    private static ISingletonServiceTwo _ServiceTwo = null; // etc ... 
    public static SummaryHeader GetBannerSummary(this IModel rfq, object requester)
    {
        Guard.ArgumentNotNull(rfq, "rfq");
        Guard.ArgumentNotNull(requester, "requester");
        if (_ServiceOne == null)
        {
            _ServiceOne = ServiceLocator.GetService<ISingletonServiceOne>(requester);
            Guard.ArgumentNotNull(_ServiceOne, "_ServiceOne");
        }
        return _ServiceOne.GetBannerSummary(rfq);
    }

在上面的文章中,ServiceLocator.GetObject()方法已在IModel上的扩展方法中使用,以定位单例注册的服务,并使用IModel在该服务上执行方法。

问题是:

  • 有没有任何模式/实践可以避免这种事情——静态类、值转换器或扩展方法中需要的DI容器
  • DI中有没有处理循环依赖关系的模式/实践
  • 如果在好的代码和交付时间之间存在权衡,你会在上面做什么

我正在考虑将GetBannerSummary()方法从扩展中移除,在这种情况下只使用IModel,但是(别笑)ValueConverters(WPF)和MarkupExtensions:0中也使用了相同的ServiceLocator

您的意见/建议感谢

我唯一一次使用ServiceLocator是在静态方法中,例如扩展方法和IValueConverters,因为不幸的是,确实没有任何其他好的方法来获取依赖关系。

唯一(稍微)更好的解决方案是将ServiceLocator调用移到一个延迟加载的属性,这样就可以在单元测试期间注入依赖项。

然而,在您的情况下,这不会发生,因为您有一个请求者属性被传递给GetService,在这种情况下,理想情况下,您需要添加一个IServiceOneFactory依赖项,您可以将请求者对象传递到该依赖项。因此:

public interface IServiceOneFactory
{
    ISingletonServiceOne Create(object requester);
}
public static class MyExtensions
{
    public static IServiceOneFactory ServiceOneFactory
    {
        get 
        {
            if( _ServiceOneFactory==null)
                _ServiceOneFactory = ServiceLocator.GetService<IServiceOneFactory>();
            return _ServiceOneFactory;
        }
        set { _ServiceOneFactory = value; }
    }
    private static IServiceOneFactory _ServiceOneFactory = null;
    private static ISingletonServiceOne _ServiceOne = null;
    private static ISingletonServiceTwo _ServiceTwo = null; // etc ... 
    public static SummaryHeader GetBannerSummary(this IModel rfq, object requester)
    {
        Guard.ArgumentNotNull(rfq, "rfq");
        Guard.ArgumentNotNull(requester, "requester");
        if (_ServiceOne == null)
        {
            _ServiceOne = ServiceOneFactory.Create(requester);
            Guard.ArgumentNotNull(_ServiceOne, "_ServiceOne");
        }
        return _ServiceOne.GetBannerSummary(rfq);
    }
}

是否可以将IServiceX注入到类中,而不是使用静态访问器类?也许将GetBannerSummary方法作为实现IModel的抽象基类的一部分?

当您不控制对象实例化时,DI不会飞行。WPF中的触发器、行为或标记扩展都属于这一类。没有在那里使用ServiceLocator的选项。

最新更新