在派生的C#类中隐藏属性

3
我有四个类,它们共享四个属性的某些排列。我目前将基类设置为抽象,并将每个属性标记为虚拟。然后在这四个派生类中,我覆盖了它使用的属性并忽略了其他属性。

问题是,我仍然可以访问每个派生类中的所有属性,无论我是否从基类中的抽象虚拟属性进行了重写。

我觉得我可能从错误的角度来解决这个问题。是否有一种明确隐藏或阻止属性的方法,或者有更好的方法?


如果您不希望所有属性都在派生类中可用,那么为什么要在基类中定义它们呢? - Mark Seemann
因为基类中的所有属性都被四个派生类中的至少一个使用,但并非全部使用。我的想法是为每个属性创建4个接口。然后派生类可以选择实现定义其所需属性的接口。 - JMS
@JMs:正如其他人也指出的那样,听起来设计应该是不同的,但我没有足够的信息去建议它应该是什么样的。 - Mark Seemann
5个回答

9

我认为您应该重新考虑继承层次结构。请考虑以下启发式规则:

如果两个或更多的类仅共享通用数据(没有共同的行为),那么这些共同数据应该被放置在一个类中,并由每个共享类包含。

如果两个或更多的类具有共同的数据和行为(即方法),那么这些类应该分别继承自一个捕获这些数据和方法的公共基类。

如果两个或更多的类仅共享一个公共接口(即消息,而不是方法),那么只有在它们将被多态地使用时,它们才应该从一个公共基类继承。


2

很抱歉,不可能在派生类中隐藏成员(这违反了继承规则)。要解决这个问题,您可以有两个级别的抽象类。第一级别有一个基类,其中包含所有应该在所有派生类中的成员,在第二级别中,您可以有特殊类,只包含您希望从此类向下继承的成员。

//Level1
public abstract class Employee
{
public string Name{get;set;}
public abstract double CalculateSalary();

}

//Level2
public abstract class CalssAEmployee:Employee
{
public int NumberOfWorkingHours{get;set;}

}

public abstract class ClassBEmployee:Employee
{
public int NumberOfSales{get;set;}
}

1
如果您不介意使用反射和类型转换,可以尝试使用帮助方法来实现类似以下示例的功能。以下示例假设有一个订单的基类,但并未在此处显示:
public abstract class Client : Entity
{
    public virtual string Name { get; set; }
    public virtual string  Comments { get; set; }
    public virtual string  Requirement { get; set; }
    public virtual string  Complaints { get; set; }
 }

public class GreatClient : Client
{
    public virtual List<GreatOrder>  Orders { get; set; }
}

public class WebClient : Client
{
    public virtual List<BadOrder> Orders { get; set; }
}

public static class ClientHelper
{
    public static IEnumerable<Order> GetOrders(this Client client)
    {
        var result = new Dictionary<Type, Func<Client>>
                         {
                             {typeof (GreatClient), () => { return ((GreatClient) client).Orders;}},
                             {typeof (WebClient), ()=> { return ((WebClient) client).Orders;}}
                         };

        return result[dto.GetType()].Invoke();
    }
}

//Client code
Client client = new WebClient();
client.GetOrders();

一个朋友向我展示了这个小模式,感谢Nap。就像我所说的,它使用反射和强制转换,但在处理基类时可以使对象模型非常优雅。

1

在派生类中删除或隐藏方法或属性会违反里氏替换原则,因此不允许。

您可以重写属性以引发异常,但这不是好的设计。

您应该仅在类中拥有实际有效的成员。

也许您想定义几个接口来具备您需要的属性,并让每个类实现所需的接口。


是的,这正是我在写这个问题时所考虑的方法。感谢您的澄清。 - JMS

0

这里有几个规则。

如果你有一个抽象类,带有虚拟属性,它们可以是受保护的或公共的,这就是外部世界所看到的。当你扩展/继承这个类时,你可以重写这些属性,但不能将它们标记为私有。私有是隐藏派生类属性的唯一方法。在抽象类中有一个私有属性将会隐藏它,使其不被子类继承。但显然在你的情况下并非如此。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接