我有一个使用 Autofac 的解决方案,我将一些方法从“视图模型”移到了服务文件中。现在,我面临一个问题,服务方法中的某些变量和引用VM属性的问题。因此我想出了,也许应该将视图模型传递给服务。
首先,我不确定是否应该这样做,以实现层分离和可测试性。但是我猜测,嘲笑应该没问题,如果我错了,请纠正我。
另一件事是,我不确定如何将VM传递给Service。使用下面可以找到的当前解决方案,我在Model道具的设置器上遇到StackOverflow
异常。事实是,在所有新想法中,这是我目前拥有的最好的技能。
另一件事,如果将VM传递到服务层是一种反模式,那么我应该如何从服务层引用VM属性?我是否应该为此创建一些包装程序,该VM和服务将引用它?
该代码将在简化示例中显示。 MainViewModel :
public class MainViewModel : ViewModelBase
{
private MainViewModel _vm;
private Person _person;
private ISomeService _someService;
public MainViewModel(ISomeService someService)
{
_person = new Person();
_someService = someService;
Name = "Slim Shady";
_vm = new MainViewModel(_someService);
Execute();
}
public string Name
{
get
{
return _person.Name;
}
set
{
_person.Name = value;
OnPropertyChanged();
}
}
private void Execute()
{
string dupa = _someService.GetTheName(_vm);
System.Windows.MessageBox.Show(dupa);
}
}
模型:
public class Person
{
public string Name { get; set; }
}
服务:
public interface ISomeService
{
string GetTheName(ViewModel.MainViewModel _vm);
}
public class SomeService : ISomeService
{
public string GetTheName(MainViewModel _vm)
{
return _vm.Name;
}
}
Autofac :
public class BootStrapper
{
public IContainer BootStrap()
{
var builder = new ContainerBuilder();
builder.RegisterType<SomeService>()
.As<ISomeService>().SingleInstance();
builder.RegisterType<MainWindow>().AsSelf();
builder.RegisterType<MainViewModel>().AsSelf().SingleInstance();
return builder.Build();
}
}
更新 还需要考虑其他一些服务也将引用Person的Name属性的情况。
答案 0 :(得分:2)
我认为这是责任倒置。
如果您的服务必须产生数据,则必须保留此数据。这不是VM的工作。
因此,在您的示例中,Name是Person的属性,而依次成为VM中getter方法的结果。
我不了解Autofac,但是我认为您的服务应该包含Person对象,并将其提供给VM(通过IoC)。
仍然,我们缺少上下文信息以获取完整且合适的答案。
如果需要在VM中实例化Person,则可以在VM中简单地告诉服务实例化它并返回它:
public MainViewModel(ISomeService someService)
{
_someService = someService;
_person = _someService.GetPerson("John");
//etc
}
public interface ISomeService
{
Person GetPerson(string name);
}
public class SomeService : ISomeService
{
private List<Person> personRepository;
//insert constructor...
public Person GetPerson(string name)
{
return personRepository.Single(person => person.Name == name);
}
}
简单地说,服务不应该了解VM,甚至不知道VM是什么。
答案 1 :(得分:2)
我应该将视图模型传递给我的服务吗?如果可以,怎么办?
不,你不应该。服务不应该依赖于视图模型。反过来。
另一件事,如果将VM传递到服务层是一种反模式,那么我应该如何从服务层引用VM属性?
你不知道。该服务应返回视图模型可能需要的任何数据,但对视图模型类型本身一无所知。
在您的示例中,服务应仅返回一个字符串:
public string GetTheName()
{
return "...";
}
如果此字符串来自视图模型,则首先使用服务检索它是没有意义的。然后,您可以直接在视图模型类中访问this.Name
。
如果服务以某种方式操纵了名称string
,则它应该接受string
作为参数并返回另一个字符串,例如:
public string GetTheName(string name)
{
return name.Trim();
}
答案 2 :(得分:1)
最终解决方案
在我创建的服务层中:
public interface IPersonService
{
string Name { get; set; }
}
public class PersonService : IPersonService
{
Person _personModel = new Person();
public string Name
{
get
{
return _personModel.Name;
}
set
{
_personModel.Name = value;
}
}
}
并进行了修改:
public interface ISomeService
{
string GetTheName(IPersonService personService);
}
public class SomeService : ISomeService
{
public string GetTheName(IPersonService personService)
{
return personService.Name;
}
}
因此,现在我同时向这两个服务注入VM,并且从SomeService
检索名称时,我正在传递注入的PersonServie
:
public class MainViewModel : ViewModelBase
{
private IPersonService _personService;
private ISomeService _someService;
public MainViewModel(ISomeService someService, IPersonService personService)
{
_personService = personService;
_someService = someService;
Name = "Slim Shady";
Execute();
}
public string Name
{
get
{
return _personService.Name;
}
set
{
_personService.Name = value;
OnPropertyChanged();
}
}
private void Execute()
{
string dupa = _someService.GetTheName(_personService);
System.Windows.MessageBox.Show(dupa);
System.Windows.MessageBox.Show(Name);
}
}