【问题标题】:How to convert List to implicit operator type如何将 List 转换为隐式运算符类型
【发布时间】:2015-12-31 12:50:07
【问题描述】:

我正在尝试学习 MVVM,并在我的 ViewModel 中添加了将模型转换为 ViewModel 的隐式运算符,反之亦然,但现在的问题是如何将模型列表转换为 ViewModel 列表?

以下是我尝试用于列表转换但不起作用的结构代码:

Person.cs

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

PersonViewModel.cs

 class PersonViewModel : Person
{
    public string FullName { get; set; }

    public static implicit operator List<PersonViewModel>(IList<Person> person)
    {
        if (person == null)
            return null;

        return person.Select(c => new PersonViewModel(c)).ToList(); // This is not working

    }

    public static implicit operator PersonViewModel(Person person)
    {
        return new PersonViewModel
        {
            FirstName = person.FirstName,
            LastName = person.LastName,
        };
    }

    public static implicit operator Person(PersonViewModel personViewModel)
    {
        return new Person
        {
            FirstName = personViewModel.FirstName,
            LastName = personViewModel.LastName,
        };
    }

}

【问题讨论】:

  • 好吧,这可能是个愚蠢的问题,但您不会错过“新”关键字吗?
  • @ViktorLaCroix 编辑了我的帖子,但这次它抱怨“PersonViewModel 不包含带 1 个参数的构造函数”
  • 它是否包含带有 1 个参数的构造函数? :D 如果不是并且你不想那样做,那么你应该做类似 person.Select(x => new PersonViewModel(){FullName = c.FullName}).ToList();
  • @ViktorLaCroix 以及 c.FullName 的来源?
  • @zee 这是你的代码,不是我们的。

标签: c# .net wpf mvvm


【解决方案1】:

尝试使用 Cast

person.Cast<PersonViewModel>().ToList();

更新

这会给您带来其他错误。您可以使用扩展方法并在需要时显式调用它们。像这样的东西(确保你最终检查空值)

    class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    class PersonViewModel : Person
    {
        public string FullName { get; set; }
    }

    static class ConversionHelpers
    {
        public static Person ToPerson(this PersonViewModel pvm)
        {
            return new Person()
            {
                FirstName = pvm.FirstName,
                LastName = pvm.LastName
            };
        }

        public static PersonViewModel ToPersonViewModel(this Person p)
        {
            return new PersonViewModel()
            {
                FirstName = p.FirstName,
                LastName = p.LastName
            };
        }

        public static IEnumerable<PersonViewModel> ToPersonViewModels(IEnumerable<Person> persons)
        {
            return persons.Select(p => p.ToPersonViewModel());
        }
    }

【讨论】:

  • 啊,我的错,编辑了我的帖子。现在它给出了“PersonViewModel 不包含接受 1 个参数的构造函数”的错误。
  • 啊,好的:)更新了我的答案。但是,我认为您最终会遇到更多错误,因为您不能在那里使用该接口,并且您可以在基类之间定义隐式运算符。
  • tnx,我尝试过强制转换,但现在它抱怨“用户定义的转换必须转换为封闭类型或从封闭类型转换”。
  • 为什么要使用运算符重载而不是创建一些映射助手?
  • 我已经考虑过使用映射助手,但我想当我有这么多模型和视图模型时,它会更难维护,所以最好每个视图模型都有隐式运算符,这将使代码看起来很干净。
【解决方案2】:

很抱歉,您的“MVVM 模式”对我来说似乎有点奇怪。
这是我对MVVM模式的理解

//Model
class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

//ModelWrapper which implements INotifyPropertyChanged if Model doesn't
//Here you can add additional properties which will serve a View's needs
class PersonModelWrapper
{
    private Person _Model;

    //Through this constructor you will create instance of modelwrapper
    //without any conversions
    public PersonModelWrapper (Person model)
    {
        _Model = model;
    }

    public string FirstName 
    { 
        get 
        { 
            return _Model.FirstName; 
        }
        set 
        {
            _Model.FirstName = value; 
        }
    }
    public string LastName
    { 
        get 
        { 
            return _Model.LastName; 
        }
        set 
        {
            _Model.LastName = value; 
        }
    }
    public string FullName
    { 
        get 
        { 
            return _Model.FirstName + " " _Model.LastName; 
        }
    }

    //Through this property you will always access current model property
    //without conversions
    public Person Model { get { return _Model; }}
}

//ViewModel which used as DataContext in the View
class PersonViewModel
{
    private PersonModelWrapper _Wrapper;
    public string Wrapper
    { 
        get 
        { 
            return _Wrapper; 
        }
        set 
        {
            _Wrapper = value; 
        }
    }
}

EDIT 作为对@Mark Feldman 评论的回答
如果 wrapper 看起来没有必要或代码臃肿,则可以跳过“ModelWrapper”,INotifyPropertyChanged 可以由 Model 本身实现。 如果您不关心模型属性更改的通知视图,那么您不需要将模型集合转换为 ViewModel 集合。
您的 ViewModel 将包含 ObservableCollection 类型的属性

class PersonViewModel
{
    public ObservableCollection<Person> Persons { get; set; }

    //if you don't care about tracking changes of collection(Add, Remove)
    //then use only List<Person> without any conversions
   public List<Person> Persons { get; set; }

}

没有包装器的视图模型

public class PersonViewModel: INotifyPropertyCahnged
{
    private Person _Model;
    public Person Model
    {
        get { return _Model; }
        set
        {
            if(Equals(_Model, value) == true)
               return;
            _Model = value;
            this.RaisePropertyChanged();
        }

        public String FullName {get {return _ModelFirstName + " " + _Model.LastName; }}

        public PersonViewModel(Person model)
        {
            _Model = model;
        }
    }
}

然后通过构造函数将模型列表转换为视图模型的集合以同样的方式发生

【讨论】:

  • 据我所知,问题与其说是通过视图模型将模型属性暴露给视图,不如说是关于如何使视图模型集合与其关联模型保持同步没有遇到代码膨胀的集合。我个人不认为 INPC 是视图模型 视图关系的专有要求,因此我倾向于将其添加到模型中,同时用于属性和集合。之后,视图模型订阅其模型的 CollectionChanged 事件,同时仍然公开您在此处显示的属性,这很简单。
  • @MarkFeldman,我创建 Wrapper 只是因为 OP 通过继承将所有属性从模型公开到视图模型。如果您在 cmets 中描述,请参阅我的更新答案
  • @MarkFeldman,据我所知,这个问题与同步模型的集合与 viewmodel 的集合无关,因为将一种类型转换为另一种类型(作为 OP 的方法)将始终创建新实例。
猜你喜欢
  • 2016-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-08
  • 1970-01-01
  • 2018-08-20
相关资源
最近更新 更多