如何创建具有限制的子类?

时间:2016-02-26 11:47:57

标签: c#

我们可以在C#中创建基类的子类,比如在SQL中创建表的视图吗?

所需行为的示例:

public class EmployeeSpecificUsage : Employee
{
    public string firstName;
    public string field1;
    public int age;

    public string Name;    //Error! Not implemented in main class
}

public abstract class Employee
{
    public string firstName;
    public string lastname;
    public int age;
    public string workTitle;
    public string field1;
    public string field2;
    public string field3;
}

目的:

  • 减少可见的字段成员数。
  • 禁止添加新字段,尊重原始模型。

4 个答案:

答案 0 :(得分:2)

您对子类化的理解不正确。子类化是扩展基类的一种方式,而不是从中取走。无论基类是什么,所有子类都会拥有它。

这与SQL中的视图不同,后者既可以删除列,也可以添加计算列。

虽然继承不允许您减少可见成员的数量,但您可以使用 composition 来执行此操作。在Employee中换行RestrictedEmployee,并仅公开您希望其他人看到的成员:

public class EmployeeSpecificUsage {
    private readonly Employee wrapped;
    public EmployeeSpecificUsage(Employee e) {
        wrapped = e;
    }
    public string firstName => wrapped.firstName;
    public string field1 => wrapped.field1;
    // Two fields above use C# 6 syntax. If it is not available,
    // use syntax below:
    public int age {
        get {
            return wrapped.age;
        }
    }
}

就禁止添加新字段而言,你不能用继承或组合来做到这一点:如果你允许继承子类(即基类不是sealed)你就能够添加新成员。组合比继承弱得多,因此您可以通过包装它们来向sealed类添加新字段。

答案 1 :(得分:1)

接口可以用作视图。

public interface IView
{
    string FirstName { get; }
    int Age { get; }
    string Name { get; }
}

public class Employee: IView
{
     // make fields private if possible         
     private string firstName;
     private string lastname;
     private int age;
     private string workTitle;
     private string field1;
     private string field2;
     private string field3;

     // implements IView.FirstName as an auto property
     public string FirstName { get; set; }

     // implements IView.Age: returns the private age field
     public int Age { get { return age;} } 

     // explicit implementation of IView.Name: visible only as IView
     string IView.Name { get { return lastName + ", " + firstName; } }
}

然后:

Employee employee1 = new Employee(); // FirstName and Age are visible on employee1
IView employee2 = new Employee(); // Name is visible, too

答案 2 :(得分:1)

接口允许您访问类的一个方面(而不是实际扩展基类的派生类)。

看看这个:

public class Employee : IEmployeeSpecificUsage
{
    public string firstName { get; }
    public string lastname { get; }
    public int age { get; }
    public string workTitle { get; }
    public string field1 { get; }
    public string field2 { get; }
    public string field3 { get; }
}

public interface IEmployeeSpecificUsage
{
    public string firstName { get; }
    public string field1 { get; }
    public int age { get; }
}

如果您通过Employee界面引用IEmployeeSpecificUsage实例,则只会"参见"界面中的内容。

但是,如果不更改"基类"则无法添加新接口,因为它必须声明它实现了这些接口。

答案 3 :(得分:0)

如果您想要提供对班级内部字段的只读访问权限,请查看公共带有getter的属性。让您的现场成员受到保护。通过这种方式,您将能够为名称属性实现自定义逻辑,该属性由firstname和lastname字段组成。

public class EmployeeSpecificUsage : Employee
{
    public string FirstName { get { return firstName; }};
    public string FullName { get { return string.Format("{0} {1}", firstName, lastName); }};
}

public class Employee
{
    protected string firstName;
    protected string lastname;
    protected int age;
    protected string workTitle;
    protected string field1;
    protected string field2;
    protected string field3;
}

一个选项是使用受保护的setter和public getter在基类中创建属性。