C# 在基类中具有所有依赖项是否是一种好的做法?
我有一个使用MVVM模式的WPF应用程序。我使用Autofac作为DI容器。与其他类似于我的应用程序一样,我有一个ViewModelBase类,它实现了INotifyPropertyChanged接口,还解析了容器中注册的依赖项:C# 在基类中具有所有依赖项是否是一种好的做法?,c#,wpf,mvvm,dependency-injection,C#,Wpf,Mvvm,Dependency Injection,我有一个使用MVVM模式的WPF应用程序。我使用Autofac作为DI容器。与其他类似于我的应用程序一样,我有一个ViewModelBase类,它实现了INotifyPropertyChanged接口,还解析了容器中注册的依赖项: public class ViewModelBase : ObservableObject { protected IErrorHandler _errorHandler; protected IEventAggregator _eventAggreg
public class ViewModelBase : ObservableObject
{
protected IErrorHandler _errorHandler;
protected IEventAggregator _eventAggregator;
protected ICustomDialogService _customDialogService;
protected IUserSettingsRepository _userSettingsRepository;
protected IReferralRepository _referralRepository;
protected Notification _notification;
protected IPrinting _printingService;
protected ILookupRepository _lookupRepository;
protected IWorklistRepository _worklistRepository;
protected IDialogCoordinator _dialogCoordinator;
public ViewModelBase()
{
_errorHandler = AppContainer.Resolve<IErrorHandler>();
_eventAggregator = AppContainer.Resolve<IEventAggregator>();
_customDialogService = AppContainer.Resolve<ICustomDialogService>();
_userSettingsRepository = AppContainer.Resolve<IUserSettingsRepository>();
_referralRepository = AppContainer.Resolve<IReferralRepository>();
_notification = AppContainer.Resolve<Notification>();
_printingService = AppContainer.Resolve<IPrinting>();
_lookupRepository = AppContainer.Resolve<ILookupRepository>();
_worklistRepository = AppContainer.Resolve<IWorklistRepository>();
_dialogCoordinator = AppContainer.Resolve<IDialogCoordinator>();
}
}
该应用程序有大约20个视图模型,所有这些模型都需要使用不同的依赖项-有时它不需要任何依赖项。每个视图模型都可以访问这些依赖项,即使它们永远不会使用它们,这是一种好的做法吗?您通常通过类构造函数或类似的方法提供依赖项,而不是从构造函数中提供依赖项。所以实际上,您的类都不应该知道DI容器的任何内容。相反,容器解析调用上下文中的依赖项,并将它们提供给类构造函数。解决依赖关系是调用方的责任,而不是类的责任。这就是控制原理反转的全部要点 话虽如此,您的依赖关系应按如下方式解决:
var errorHandler = AppContainer.Resolve<IErrorHandler>();
var eventAggregator = AppContainer.Resolve<IEventAggregator>();
var myModel = new MyModel(errorHandler, eventAggregator);
ViewModelBase类出现以下问题:
它使用。这使得类的依赖关系不明显。
它将其依赖项暴露于其派生项,而不是将其行为隐藏于派生项,从而导致派生项违反规则。
基类总是与它的导数强耦合,如果它有这种情况,它的行为也会如此。这会使测试复杂化,并且通常会使导数复杂化。
因此,使用包含依赖项或易失性行为(即您希望在测试套件中模拟、替换或拦截的行为)的基类被认为是一个坏主意
与使用基类对公共依赖项进行分组不同,其他方法更有效,例如:
使用装饰器或拦截器来应用横切关注点
用于隐藏依赖项组及其行为。
将衍生工具分解为更小的类,这样它们就不需要太多依赖关系。
使用与服务定位器反模式相反的构造函数注入。
您的类应该具有正常工作所需的依赖项。说到这里,您通常通过类构造函数或类似的方法提供依赖项。不是从构造函数内部。所以实际上,您的类都不应该知道DI容器的任何内容。相反,contaienr在调用上下文中解析依赖项并将它们提供给类构造函数。我在问题中应该提到的是,最初我使用构造函数注入,其中每个视图模型只请求它所需的依赖项,但这意味着对于位于父-子viewmodel层次结构,我必须在实例化时通过链向下传递该依赖关系。这变得相当混乱,所以保存依赖项的viewmodelbase类是我的解决方案。@rejy11是的,你应该提到这一点。无论如何,这就是DI的工作方式。代码中只有一个点构建了完整的依赖关系图。所有其他类都不应该为DI容器费心。谢谢您的反馈。根据我上面的评论,我在视图模型库中使用所有依赖项提出的这个解决方案只是我试图看看它是否能解决我的问题。问题是,当我的一个视图模型位于父子层次结构的底部时,需要依赖关系,它需要从链的开始传递到链的结束,导致许多视图模型在实例化时将依赖关系传递给下一个视图模型-这有意义吗?没有,那没有道理。这意味着您使用的是方法注入,您应该尽量少用。相反,使用组合,并使用构造函数注入构建视图模型的层次结构。每个视图模型都可以有自己的依赖关系;这些依赖项不应传递给其他依赖项,如其他视图模型
var customDialogService = AppContainer.Resolve<ICustomDialogService>();
var userSettingsRepository = AppContainer.Resolve<IUserSettingsRepository>();
var myModel = new MyModel2(customDialogService, userSettingsRepository);