我应该将视图模型传递给我的服务吗?如果可以,该如何做?

时间:2019-06-18 09:51:37

标签: c# wpf mvvm service autofac

我有一个使用 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属性的情况。

3 个答案:

答案 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);
        }
    }