我正在开发一个大型的遗留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对其执行方法。
问题是:
我想将GetBannerSummary()方法从扩展中移出,在这种情况下只移动IModel,但是(不要笑)还有在ValueConverters(WPF)和MarkupExtensions中使用相同ServiceLocator的情况:0 < / p>
您的意见/建议表示赞赏
答案 0 :(得分:2)
我唯一一次使用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);
}
}
答案 1 :(得分:2)
是否可以选择将IServiceX
注入您的类而不是使用静态访问器类?也许将GetBannerSummary
方法作为实现IModel
的抽象基类的一部分?
当您不控制对象实例化时,DI不会飞行。 WPF中的触发器,行为或标记扩展属于该类别。在那里没有使用ServiceLocator的选项。