2012-01-13 2 views
3

Предположим, что у нас есть 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; 
    } 
} 

Моя проблема в том, что я хотел бы только DoSomeWorkCreateChild) быть доступным для общественности, но в моей «архитектуре» Я вынужден сделать Calculate общественность также. Или я?

Любой вход будет очень оценен.

Edit:

Calculate не могут быть защищены из-за этой линии в Child

double result = _Container.Calculate(); 

, которое вызывало бы произойти ошибка сборки.

+0

Не совсем понятно, что вы пытаетесь выполнить, так как ваш код выглядит неполным. Например, поле '_Value' нигде не используется, а также параметр' value' в методе DoSomeWork. Было бы полезно показать, как они должны взаимодействовать. Сейчас DoSomeWork выглядит излишним, и 'Calculate', кажется, выполняет всю работу (и поэтому должен быть общедоступным). С другой стороны, может оказаться, что 'Calculate' вообще не принадлежит к этому классу, что я подозреваю с первого взгляда. – Groo

+0

@Groo _Value используется в классе 'Root'. Я редактировал вопрос, чтобы «использовать» параметр 'value'. Я согласен, что именно «архитектура», скорее всего, виновата. Общая идея заключается в том, что потребитель должен создать экземпляр класса «Root», а затем порождать детей с помощью «CreateChild» при использовании DoSomeWork. В идеале все остальные участники не должны быть видны. (который включает 'Child' ctor) – clearpath

+0

Я обновил свой ответ. – Groo

ответ

6

Нет, вы можете сделать это protected. Таким образом, ваш производный класс будет по-прежнему иметь доступ к нему и сможет его переопределить, но он не будет разрешен публично.

Хорошее мышление, это именно то, как это сделать: переопределить как можно меньше и скрыть как можно больше.

- Edit -

Так как это, вероятно, упрощенный пример того, что вы на самом деле делаете, я могу предоставить только предположение того, что делают эти методы, но здесь оно идет.

У меня такое чувство, что метод 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; 
    } 
} 
+0

+1 особенно для комментария «хорошего мышления». Совершенно верно, и стоит отметить. –

1

Вы можете объявить Calculate, как protected, и он будет только быть доступным для продления классов.

Это та же концепция, что и protected int _Value; - у вас есть доступ к ней в текущем классе и во всех его дочерних элементах, но не снаружи.

1

Не должно быть public. Его можно сделать protected.

0

неправильный ... вам не нужно делать PUBLIC ... вы можете сделать PROTECTED, что означает, что любой дочерний производный класс может использовать функцию, но ее НЕ видно другим элементам управления вне его.

0

Вы можете использовать eigther protected (= только внутри класса и в его унаследованных классов, доступных) или internal (= только внутри одной и той же сборки доступны). См. HERE.

0

Вы могли бы сделать это:

  1. protected - доступен только для типов, которые являются производными от него.
  2. internal - Доступно только для типов в одной и той же сборке (или в узле с сильным именем, объявленном как разрешенный для просмотра внутренних типов сборки).
  3. protected internal - Позволяет обоим вышеперечисленным; Производные типы и другие типы в одной сборке могут обращаться к нему.

.NET также имеет тип доступа, который ограничивает что-то к тому, чтобы быть как производный тип И в той же сборке, но C# не поддерживает его (предположительно потому, что вы можете получить с internal в этом случае и было бы сложным думать о имени, которое не было легко путать с protected internal).

В этом случае это почти наверняка будет protected.

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.Calculate() в Derived является незаконным, если б не известен во время компиляции, чтобы быть экземпляром производных или лучше . (Причина: защищенные члены доступны для подклассов, объект, на который ссылается b, может быть совершенно другого подкласса Base, а Derived не имеет доступа к защищенному методу этого класса, потому что Derived не является его производным.)

Расчет может быть внутренним, охраняемым внутренним или государственным.

Однако там is способ сделать Расчет защищенным. Если вы хотите сделать конец перспективе вокруг правила о защищаемом что ресивер должен быть более производного типа, то сделать базовый класс делать грязную работу за вас: чувство

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

Make?

+0

Да, это очень. Но, хотя технически это был бы правильный ответ, я награждаю ответ на решение Groos, потому что он вдохновил на улучшение моей «архитектуры», – clearpath

Смежные вопросы