使用安全向下转换的类设计选项

在经历了向下倾斜(见[我的原帖] )并制作[深拷贝]之后 ,我发现[这个同名文章]在C ++中提出了如何处理这个问题的建议。 我非常兴奋,我在C#中实现了如下:

public partial class User { virtual public Employer GetEmployer() { return null; } ... } public partial class Employer { public override Employer GetEmployer() { return this; } ... } 

然后我像这样使用:

 User u = GetUser(); Employer e = u.GetEmployer(); 

但是(我想,毫不奇怪),从不调用覆盖并返回null。


我试图解决的问题是我收集的将是一个非常常见的用例:我得到一些我需要存储的数据,但它不完整。 后来我获得了更多数据,并用它来改进(低估)我对世界的理解。

在这种特殊情况下,我从使用我网站的人那里得到一个电子邮件地址,所以我知道他们是User ,但总的来说,我不知道其他任何关于他们的信息。 后来(当他们填写表格时),我知道他们实际上是Employer ,所以我需要低估我的User

这里的正确方法是什么?

我回答了你以前的一个问题。 你正试图解决一些无法解决的问题。 这里的解决方案是不使用inheritance。 为什么因为inheritanceis a关系。 所以如果你有:

 public class User { } public class Employee : User { } 

您有这种关系Employeee is User您没有反向关系User is Employee 。 但是,从UserEmployee转换,您正在努力做到这一点。 User实例不能转发给Employee (除了我之前回答中提到的情况 – 但你没有这种情况)。

使用这种方法,您将以面向对象的方式解决它,而无需inheritance转换或其他任何东西。

 public class User { public virtual EmployeeData { get; set; } } public class EmployeeData { } 

这种方法改变了你的设计is a has a关系。 在这种情况下, EmployeeData是以1 – 0..1关系映射的独立实体(这将导致数据库中的两个表)。 如果您对UserEmployeeData都存储在同一个表中的事实感到满意,您也可以使用1 – 1关系或ComplexType。

您的示例中唯一缺少的部分是Employer不会从Userinheritance。

将您的声明更改为:

 public partial class Employer : User { // ... } 

你应该好好去。 我不确定我会走这条路。 我可能只是使用as关键字安全地进行我的投射:

 var user = GetUser(); var employer = user as Employer; // if the cast failed, employer will be null if(employer != null) { // Work with employer } 

你应该遵循状态模式 :

这是对象在运行时部分更改其类型的简洁方法。

然后,您可以与原型模式混合搭配:

[使用]一个原型实例,克隆它以生成新对象。

你可以得到这样的东西:

 // State pattern: public "wrapper" public class User { UserState state = UserState.CreateUser(); public void SetIsEmployer () { // Use UserState.IsEmployer() method to transition to the // Employer state state = state.IsEmployer (); } public User Employer { get {return state.Employer.User;} } } // State pattern: User state internal class UserState { // protected so that only CreateUser() can create instances. protected UserState () { } public User User { get {/* TODO */} } public virtual UserState Employer { get {return null;} } // Creates a default prototype instance public static UserState CreateUser () { return new UserState (); } // Prototype-ish method; creates an EmployerState instance public virtual UserState IsEmployer () { return new EmployerState (/* data to copy...*/); } } // State pattern: Employer state class EmployerState : UserState { internal EmployeeState () { } public override UserState Employer { get {return this;} } } 

如果您的公共User类型需要更多“状态转换”,则只需在UserState类型上提供更多类(每个状态一个)和prototype-ish方法,以创建适当的目标状态类型。 User.state始终是User的当前状态。 此设置允许您在运行时更改实例的表观运行时类型。