使用安全向下转换的类设计选项
在经历了向下倾斜(见[我的原帖] )并制作[深拷贝]之后 ,我发现[这个同名文章]在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
。 但是,从User
到Employee
转换,您正在努力做到这一点。 User
实例不能转发给Employee
(除了我之前回答中提到的情况 – 但你没有这种情况)。
使用这种方法,您将以面向对象的方式解决它,而无需inheritance转换或其他任何东西。
public class User { public virtual EmployeeData { get; set; } } public class EmployeeData { }
这种方法改变了你的设计is a
has a
关系。 在这种情况下, EmployeeData
是以1 – 0..1关系映射的独立实体(这将导致数据库中的两个表)。 如果您对User
和EmployeeData
都存储在同一个表中的事实感到满意,您也可以使用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
的当前状态。 此设置允许您在运行时更改实例的表观运行时类型。