我们假设我们有3个类:Base
,Root
和Child
。
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();
会导致构建错误。
答案 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)
你可以做到:
protected
- 仅对从中派生的类型可访问。internal
- 只能访问同一个程序集中的类型(或声明为允许查看此程序集内部类型的强名称程序集)。protected internal
- 允许以上两种情况;同一程序集中的派生类型和其他类型都可以访问它。 .NET还有一种访问类型,它限制某些东西必须同时是同一个程序集中的派生类型,但C#不支持它(可能是因为在这种情况下你可以使用internal
对于一个不容易与protected internal
混淆的名称,这将是一个棘手的想法。
在这种情况下,几乎可以肯定是protected
。