2012-06-17 3 views
3

У меня есть несколько классов, и у меня возникают проблемы с доступом к свойствам, определенным в подклассах, из других методов класса.C# Доступ к свойству подкласса

У меня есть базовый класс Section и несколько подклассов, например. SectionPlane : Section. В каждом подклассе задан другой набор полей и свойств (в SectionPlane, частное поле _t и общедоступное свойство t, а в SectionExtruded : Section У меня есть личное поле _A и общедоступное свойство'A ').

Раздел Класс

// General section object 
public abstract class Section 
{ 
    public Section() 
    {} 
} 

класса Plane Раздел

// Section object representing a plane with thickness t 
public class SectionPlane : Section 
{ 
    private double _t; 

    public SectionPlane(double t) 
    { 
     this.t = t; 
    } 

    public double t 
    { 
     get 
     { 
      return _t; 
     } 
     set 
     { 
      _t = value; 
     } 
    } 
} 

Класс Экструдированный Раздел

// Section object of some geometry with cross section area A extruded along the element it is assigned to. 
public class SectionExtruded : Section 
{ 
    private double _A; 

    public SectionExtruded(double A) 
    { 
     this.A = A; 
    } 

    public double A 
    { 
     get 
     { 
      return _A; 
     } 
     set 
     { 
      _A = value; 
     } 
    } 
} 

Проблема возникает, когда я из любого подкласса класса Element пытается получить доступ к свойствам, поскольку они не установлены в базовом классе Section, например. в элементе Solid2D : Element:

класса Element

public abstract class Element 
{ 
    private Section _section; 

    public Element(Section section) 
    { 
     this.section = section; 
    } 

    public Section section 
     { 
      get 
      { 
       return _section; 
      } 
      set 
      { 
       _section = value; 
      } 
     } 
    } 
} 

Класс Твердая 2D Элемент

// Solid2D elements can only have sections of type SectionPlane 
public class Solid2D : Element 
{ 
    public Solid2D(SectionPlane section) 
     : base(section) 
    { 
    } 

    public void Calc() 
    { 
     double t = section.t; // This results in error 'Section' does not contain a definition for 't' and no extension method 't' accepting a first argument of type 'Section' could be found (are you missing a using directive or an assembly reference?) 
    } 
} 

Бар Элемент

// Bar elements can only have sections of type SectionExtruded 
public class Solid2D : Element 
{ 
    public Solid2D(SectionExtruded section) 
     : base(section) 
    { 
    } 

    public void Calc() 
    { 
     double A = section.A; // This results in error 'Section' does not contain a definition for 'A' and no extension method 'A' accepting a first argument of type 'Section' could be found (are you missing a using directive or an assembly reference?) 
    } 
} 

Есть ли способ получить доступ к моей собственности t без необходимости включать ее в базовый класс Section? Это было бы очень полезно, так как не все разделы, которые я буду использовать, имеют те же свойства.

+0

Чтобы получить доступ к свойствам 'SectionPlane', вы должны сначала преобразовать тип объекта в' SectionPlane'. Тим С. сказал это первым, но пост Оливье Жако-Дескомба гораздо более ясен по этому вопросу. – Trisped

+0

У меня был тот же вопрос несколько недель назад (http://stackoverflow.com/questions/10804578/design-pattern-for-specialized-properties-in-subclasses), и я должен сказать, что вы дали прекрасное объяснение проблемы далеко лучше, чем моя. Во всяком случае, моим решением было добавить поле 'SectionPlane sectionPlane' в' Solid2D' и инициализировать его в конструкторе. В моем случае этого было достаточно, поскольку он был только для чтения. Возможно, вам придется переопределить свойство 'section' (setter). –

ответ

6

Поскольку вы знаете, что это может быть только SectionPlane вы можете бросить его

double t = ((SectionPlane)section).t; 

Если вы не уверены, есть ли у вас раздел правильный тип, вы можете использовать ключевое слово as

double t = 0; 
var sectionPane = section as SectionPlane; 
if (sectionPane != null) { 
    t = sectionPane.t; 
} 

as не делает Тре ow исключение, если раздел имеет другой тип, но вместо этого возвращает null.

Или вы можете просто проверить

double t = 0; 
if(section is SectionPlane) { 
    t = ((SectionPlane)section).t; 
} 

, но это менее элегантно, чем при использовании as, так как вы должны проверить тип, а затем бросил его; но литье делает этот тест снова внутренне.

Используя новый шаблон сопоставления, введенный в C# 7.0 вы можете написать:

double t = 0; 
if(section is SectionPlane sp) { 
    t = sp.t; 
} 

Но если у вас есть, чтобы выполнение проектно такой тест, вопрос в том, является ли ваш подход является правильным в объектно- ориентированный смысл. Если вы переместите метод Calc в абстрактный класс Section и пусть каждый класс выполнит собственный расчет, то не потребуется вводить тест или кастинг.

В Section:

public abstract void Calc(); 

В SectionPlane

public override void Calc() 
{ 
    var x = t; // No casting or type test required. 
} 
+0

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

+0

Спасибо! Пытался бросить раньше, но пропустил несколько скобок, которые сделали magic =) – sehlstrom

0

Вот несколько вариантов:

  1. Изменить Element.section к SectionPlane.
  2. Отрасль section до SectionPlane в Calc().
  3. Добавить t в Section.
  4. сделать интерфейс (например, IHasT), который имеет свойство t, сделать SectionPlane осуществить это, и изменить Element.section к IHasT.
  5. (если применимо) изменение public abstract class Element к public abstract class Element<T> where T : Section, изменить section к типу T, и сделать Solid2D : Element<SectionPlane>
+0

Спасибо за ваш ответ! 1.Невозможно, так как не все элементы будут использовать SectionPlane. 2. Я пробовал это без везения. 3. Как я уже говорил, не то, что я хочу. 4. Можете ли вы разработать этот вариант? Я не понимаю, как я могу изменить 'Element.section' на' IHasT' 5. Попробуем посмотреть, какие последствия это дает остальной части кода. – sehlstrom

+0

Это отдельные возможности, а не список заказов одного решение, так что проверьте 2-5. –

0

Если вы знаете тип раздела элемента наследникам будет использовать, я хотел бы сделать элемент базового класса родовое :

public abstract class Element<SectionType> 
    where SectionType:Section 
{ 
    //.... 
} 

Вы можете включить тип элемента по умолчанию, с помощью базового класса:

public abstract class Element:Element<Section> 
{ 
    //.... 
} 

И известные элементы могут наследовать сильно типизированных:

public class Solid2D : Element<SectionPlane> 
1

Я бы сказал, чтобы положить вашу собственность "т" в разделе базового класса, если это принадлежит там.

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