成员的继承和可见性

时间:2012-01-13 11:39:05

标签: c# oop inheritance

我们假设我们有3个类: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。还是我?

非常感谢任何输入。

修改

由于Calculate

中的这一行,无法保护

Child

double result = _Container.Calculate();

会导致构建错误。

8 个答案:

答案 0 :(得分:8)

让我们从你的例子中删除不必要的瑕疵:

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;
    }
}

问题是“计算必须公开吗?”

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

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

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

但是,一种使计算受保护的方法。如果你想围绕关于受保护的接收者的规则进行最终运行,那么让基类为你做脏工作

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;
    }
}

有意义吗?

答案 1 :(得分:6)

不,你可以成功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;
    }
}

,您可以在每次调用时将“计算器”传递给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;
    }
}

答案 2 :(得分:1)

您可以将Calculate声明为protected,并且只能访问扩展类。

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

答案 3 :(得分:1)

不应该是public。它可以是protected

答案 4 :(得分:0)

不正确......您不必执行PUBLIC ...您可以执行PROTECTED,这意味着任何子派生类都可以使用该函数,但它对其它控件不可见。

答案 5 :(得分:0)

不,你可以成功protected

答案 6 :(得分:0)

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

答案 7 :(得分:0)

你可以做到:

  1. protected - 仅对从中派生的类型可访问。
  2. internal - 只能访问同一个程序集中的类型(或声明为允许查看此程序集内部类型的强名称程序集)。
  3. protected internal - 允许以上两种情况;同一程序集中的派生类型和其他类型都可以访问它。
  4. .NET还有一种访问类型,它限制某些东西必须同时是同一个程序集中的派生类型,但C#不支持它(可能是因为在这种情况下你可以使用internal对于一个不容易与protected internal混淆的名称,这将是一个棘手的想法。

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