成员的继承和可见性

本文关键字:可见性 继承 成员 | 更新日期: 2023-09-27 18:20:07

假设我们有三个类:BaseRootChild

public abstract class Base
{
    protected int _Value;
    public double DoSomeWork(int value)
    {
        _Value = value;
        double result = Calculate();
        return result;
    }
    public abstract double Calculate();
    public Child CreateChild(int length)
    {
        return new Child(this);
    }
}
public class Root : Base
{
    public override double Calculate()
    {
        return _Value;
    }
}
public class Child : Base
{
    readonly Base _Container;
    public Child(Base container)
    {
        _Container = container;
    }
    public override double Calculate()
    {
        double result = _Container.Calculate();
        // do some more calculation
        return result;
    }
}

我在这里的问题是,我希望只有DoSomeWork(和CreateChild)可以公开访问,但在我的"体系结构"中,我也必须公开Calculate。还是我?

任何意见都将不胜感激。

编辑:

由于Child 中的这一行,Calculate无法得到保护

double result = _Container.Calculate();

这将导致发生构建错误。

成员的继承和可见性

让我们从您的示例中删除不必要的cruft:

public abstract class Base
{
    public abstract double Calculate();
}
public class Derived : Base
{
    private Base b;
    public override double Calculate()
    {
        double r = b.Calculate();
        // Perform additional calculations on r
        return r;
    }
}

问题是"Calculate必须公开吗?"

Calculate不能是私有的,因为私有虚拟机在C#中是非法的。

如果b在编译时不是Derived或更好的实例,则Calculate无法受到保护,因为对Derived中b.Calculate()的调用是非法的。(原因是:受保护的成员可以访问子类;b引用的对象可能属于Base的一个完全不同的子类,并且Derived不允许访问该类的受保护方法,因为Derived不是从它派生的。)

计算可以是内部的、受保护的内部的或公共的。

但是,有一种方法可以使Calculate受到保护。如果你想围绕受保护的接收器被要求是更派生类型的规则进行最终运行,那么让基类为你做肮脏的工作

public abstract class Base
{
    protected static double Calculate(Base b) 
    { 
        // perfectly legal inside Base:
        return b.Calculate(); 
    }        
    protected abstract double Calculate();
}
public class Derived : Base
{
    private Base b;
    protected override double Calculate()
    {
        double r = Base.Calculate(b);
        // Perform additional calculations on r
        return r;
    }
}

有道理吗?

不,您可以将其设为protected。这样,派生类仍然可以访问它并能够覆盖它,但它不会被公开允许。

好主意,这正是做到这一点的方法:尽可能少地覆盖,尽可能多地隐藏。

-编辑-

由于这可能是一个你实际在做什么的简化例子,我只能猜测这些方法的作用,但它到此为止。

我有一种感觉,Calculate方法可能不属于您的Base类。它似乎提供了DoSomeWork使用的辅助计算结果。继承通常在基类有一些公共计算要"提供"给派生类时使用,这样就不必重复自己的计算。

例如,假设您的DoSomeWork方法有一些特定的功能,这些功能不会更改,但需要首先执行"外部"计算。如果您开始为外部计算创建一个简单的单独界面:

interface ICalculator
{
    double Calculate();
}

您可以定义此接口的不同实现。您可以从创建一个简单的实现(类似于Root功能)开始:

class SimpleCalculator : ICalculator
{
    readonly double _value;
    public SimpleCalculator(double value)
    {
       _value = value;
    }
    public double Calculate()
    {
       return _value;
    }
}

您还可以轻松地将现有的实现封装在更复杂的类中(类似于CreateChild想要做的):

// for the rest of the world, this is an ICalculator like any other
class CalculatorWrapper : ICalculator
{ 
    readonly ICalculator _base;
    public CalculatorWrapper(ICalculator baseCalc)
    {
       _base = baseCalc;
    }
    public double Calculate()
    {
       double value = _base.Value; 
       return 2 * value;
    }
}

然后,您的实际类需要将此功能用于一些预期的"额外工作":

interface MyWorker
{
    double DoSomeWork(int value);
}
class YourClass
{
    readonly ICalculator _calc; 
    readonly double _someOtherValue;
    public YourClass(ICalculator calc, double someOtherValue)
    {
       _calc = calc;
       _someOtherValue = someOtherValue;
    }
    public double DoSomeWork(int value)
    {
       // use whatever you get from your calc
       double externalValue = _calc.Calculate();
       // and do some "actual work"
       return _someOtherValue + value + externalValue;
    }
}

或者,您可以在每次调用时将"calculator"作为参数传递给DoSomeWork,并将复杂类更改为类似以下内容:

interface MyWorker
{
    double DoSomeWork(ICalculator calc, int value);
}
class YourClass
{
    public double DoSomeWork(ICalculator calc, int value)
    {
       // use whatever you get from your calc
       double externalValue = calc.Calculate();
       // and do some "actual work"
       return _someOtherValue + value;
    }
}

您可以将Calculate声明为protected,并且它只能用于扩展类。

它与protected int _Value;的概念相同——您可以在当前类及其所有子类中访问它,但不能从外部访问。

它不应该是public。可制成protected

不正确。。。你不必公开。。。您可以执行PROTECTED,这意味着任何派生的子类都可以使用该函数,但它对它之外的其他控件不可见。

不,您可以使其成为protected

您还可以使用protected(=仅在类内部及其可访问的继承类中)或internal(=仅可在同一程序集中访问)。请参阅此处。

你可以做到:

  1. protected-仅对从其派生的类型可访问
  2. internal-仅可访问同一程序集中的类型(或声明为允许查看此程序集的内部类型的强名称程序集)
  3. protected internal-允许以上两种情况;派生类型和同一程序集中的其他类型都可以访问它

.NET还有一个访问类型,它限制某些东西必须是同一程序集中的派生类型AND,但C#不支持它(可能是因为在这种情况下,您可以使用internal,而且考虑一个不容易与protected internal混淆的名称会很棘手)。

在这种情况下,它几乎可以肯定是protected