Расширение функциональности полей базового класса

#c# #class #inheritance #derived-class

#c# #класс #наследование #производный класс

Вопрос:

У меня есть следующий код, который представляет ребра и узлы графа (упрощенный для вопроса):

 public class Node
{
}

public class Edge
{
    public Node Source { get; set; }
    public Node Target { get; set; }
}
  

Теперь я хочу расширить эти классы для описания моей топологии:

 public class MineNode : Node
{
    public double FanPressure { get; set; }
}

public class MineTunnel : Edge
{
    public double Length { get; set; }
    public double CrossSectionArea { get; set; }

    public MineTunnel()
    {
        Source = new MineNode();
        Target = new MineNode();
    }
}
  

Проблема в том, что я хочу получить доступ к дополнительным данным, предоставляемым MineNode при использовании Source и Target свойств, но я могу получить доступ только к Node полям, потому что они объявлены в базовом классе:

 MineTunnel t = new MineTunnel();
Console.WriteLine(t.Source.FanPressure); //Error
  

Единственный способ получить доступ FanPressure — привести Source к MineNode , но таким образом код становится уродливым.

 Console.WriteLine(((MineNode)t.Source).FanPressure); //OK
  

Возможно, другим способом является использование каких-либо обобщений в объявлении базового класса. Но я не уверен, что это хорошая практика в моей ситуации.

Итак, как я могу решить такую проблему — расширить функциональность полей базового класса?

Спасибо.

Ответ №1:

Вы могли бы определить свой Edge тип как универсальный, с ограничениями:

 public class Edge<TNode> where TNode: Node
{
  public TNode Source { get; set; }
  public TNode Target { get; set; }
}
  

С помощью которого вы могли бы переопределить свой MineTunnel тип как:

 public class MineTunnel : Edge<MineNode>
{
  // Stuff
}
  

Ответ №2:

Я думаю, что дженерики — это правильный путь…

Попробуйте это:

 public class Node
{

}

public class Edge<S, T>
    where S : Node
    where T : Node
{
    public S Source { get; set; }
    public T Target { get; set; }
}
  

Затем вы можете расширить классы Node и Edge с помощью:

 public class MineNode : Node
{
    public double FanPressure { get; set; }
}

public class MineTunnel : Edge<MineNode, MineNode>
{
    public double Length { get; set; }
    public double CrossSectionArea { get; set; }

    public MineTunnel()
    {
        Source = new MineNode();
        Target = new MineNode();
    }
}
  

Пожалуйста, поправьте меня, если это неправильно или не работает … 🙂

 MineTunnel t = new MineTunnel();
Console.WriteLine(t.Source.FanPressure); // Now this works without errors ;)
  

Комментарии:

1. Почему у вас есть узел, расширяющий границы?

2. О, извините, это было не намеренно. Думаю, это проскользнуло туда, когда я писал заголовок класса

3. Почему исходный и целевой узлы имеют разные типы?

4. Потому что я думал, что для ребра было бы возможно перейти от т.е. MineNode к YourNode. Вы могли бы указать разные типы для источника и назначения.

5. Разные универсальные типы — это нормально, но я все равно всегда буду использовать одно и то же. Все ответы хороши и правильны, но вы были немного быстрее.