在扩展方法中需要Factory类
本文关键字:Factory 扩展 方法 | 更新日期: 2023-09-27 18:21:40
我正在开发一个大型遗留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的选项。