如果 BusinessObject 和 Person 类(以及它们的 VM 对应物)是抽象的,那么您可以像这样访问正确的模型:
public abstract class BusinessObjectViewModel : ViewModelBase
{
protected abstract BusinessObject BusinessObject { get; }
protected BusinessObject Model { get { return this.BusinessObject; } }
}
public abstract class PersonViewModel : BusinessObjectViewModel
{
protected abstract Person Person { get; }
protected new Person Model { get { return this.Person; } }
protected override sealed BusinessObject BusinessObject
{
get { return this.Model; }
}
}
public class CustomerViewModel : PersonViewModel
{
protected new Customer Model { get; set; }
protected override sealed Person Person
{
get { return this.Model; }
}
}
public class EmployeeViewModel : PersonViewModel
{
protected new Employee Model { get; set; }
protected override sealed Person Person
{
get { return this.Model; }
}
}
这样,每个派生的 VM 类通过实现抽象属性并隐藏基类 Model 属性为其基本 VM Model 属性提供值,因此每个 VM 都使用适当类型的 Model 属性(因此不需要强制转换)。
这种方法有其优点和缺点:
好处:
缺点:
- 仅当基类(BusinessObjectViewModel 和 PersonViewModel)是抽象类时才有效,因为必须存在由派生类实现的抽象属性,并为这些基类提供模型实例。
- 不应在基类构造函数中访问模型属性,因为构造函数链接从基类到最派生的类。派生最多的类构造函数会设置模型,所以基类构造函数会被提前调用以查看它。这可以通过将 Model 作为参数传递给构造函数来避免。
- 派生类不需要看到 BusinessObject 和 Person 属性。EditorBrowsableAttribute 可能在此处对 Intellisense 有所帮助,但仅当代码由不同 Visual Studio 解决方案中的另一个程序集使用时(这是 Visual Studio 特定的行为)。
- 表现。当基类访问模型时,代码会经过一系列虚拟属性。但是由于实现的抽象属性被标记为密封,虚拟表查找不应该有太多的性能下降。
- 不能很好地扩展。对于深层类层次结构,代码将包含许多不必要的成员。
另一种方法是:
public class BusinessObjectViewModel : ViewModelBase
{
protected BusinessObject Model { get; private set; }
public BusinessObjectViewModel(BusinessObject model)
{
this.Model = model;
}
}
public class PersonViewModel : BusinessObjectViewModel
{
protected new Person Model { get { return (Person)base.Model; } }
public PersonViewModel(Person model)
: base(model)
{
}
}
public class CustomerViewModel : PersonViewModel
{
protected new Customer Model { get { return (Customer)base.Model; } }
public CustomerViewModel(Customer model)
: base(model)
{
}
}
public class EmployeeViewModel : PersonViewModel
{
protected new Employee Model { get { return (Employee)base.Model; } }
public EmployeeViewModel(Employee model)
: base(model)
{
}
}
好处:
- 基类不需要是抽象的。
- 模型可以通过基类构造函数访问。
- 没有不必要的附加属性。
缺点:
基于这个分析,我会选择第二个选项,因为修复它的唯一缺点,铸造性能,将是不必要的微优化,在 WPF 上下文中不会被注意到。