У меня есть следующий 3 класс:класса проблема вывода
class Node {
public Node Parent;
// Edit: to clarify, each of these classes has many fields and methods
public void Method1() { /*...*/ }
public void Method2() { /*...*/ }
/* ... */
public void Method30() { /*...*/ }
}
class Element : Node { public Dictionary<string, string> Attributes; }
class Document : Element { }
мне нужно иметь возможность определить ExtraNode
, ExtraElement
и ExtraDocument
так, что они являются эквивалентом копирования кода выше, добавив несколько дополнительных полей к Node
класса, и предваряя все классы с «Extra», например, так:
class ExtraNode { public Node Parent; public int Priority; }
class ExtraElement : ExtraNode { public Dictionary<string, string> Attributes; }
class ExtraDocument : ExtraElement { }
Что является лучшим для достижения этой цели? Я думал о интерфейсах (ExtraNode : Node, IExtra
), но затем (ExtraElement is ExtraNode) == false
.
Я также думал о перезаписи классов в качестве дженериков (Node<T>, Element<T>, Document<T>
), а затем использовать их, чтобы определить новые классы (ExtraNode : Node<MyExtraClass>
и так далее), но она по-прежнему приводит к проблеме (ExtraElement is ExtraNode) == false
потому (Element<MyExtraClass> is Node<MyExtraClass>) == false
.
Итак, каков наилучший способ достижения этого, без копирования/вставки всего документа и изменения вручную? Мне нужно будет это делать не один раз.
Edit: уточнить, что мне нужно, чтобы быть в состоянии сделать, мне нужен следующий код для работы:
// this should accept an ExtraNode, an ExtraElement or an ExtraDocument:
void doSomethingWithANode(ExtraNode extraNode) { ... }
Edit 2: Предложение Кирки о реализации интерфейсов (на примере кода Timwi в) в моем случае нецелесообразно, потому что каждый класс имеет много полей и методов (и всего около 8 классов), поэтому мне пришлось бы копировать каждый из них для каждой группы «Extra». Например, так будут выглядеть классы узлов:
class INode {
INode Parent { get; }
void Method1();
void Method2();
/* ... */
void Method30();
}
class ExtraNode {
public int Priority { get; } // extra
public INode Parent { get; } // THIS IS WRONG, THIS SHOULD BE ExtraNode NOT INode
public void Method1() { ... } // here I have to define the entire method
public void Method2() { ... }
/* ... */
public void Method30() { ... }
}
class SuperNode {
public string Superpower { get; } // extra
public INode Parent { get; } // THIS IS WRONG, THIS SHOULD BE SuperNode NOT INode
public void Method1() { ... } // here I have to define the entire method AGAIN
public void Method2() { ... } // all methods are identical to the ones in ExtraNode
/* ... */
public void Method30() { ... } // this is unnecessary code duplication
}
Так 30 методов дублируются каждый раз. И это применимо ко всем другим классам. С помощью этого метода я бы дублировал так много, я практически дублировал весь код. Было бы проще просто скопировать/вставить весь класс, переименовать и добавить к ним дополнительные поля.
Если вы использовали интерфейсы, то у вас предположительно были бы IExtraNode, IExtraElement и IExtraDocument. Элемент ExtraElement будет определен как ExtraElement: Элемент, IExtraElement и IExtraElement будут определены как IExtraElement: IExtraNode. С помощью этой установки (ExtraElement является IExtraNode) == true. –
@ Кирк благодарит за предложение, но мне нужно, чтобы ExtraElement был как ExtraNode, а не IExtraNode. Чтобы проиллюстрировать это, я должен уметь: ExtraNode = someExtraElement ?? someExtraNode. – manixrock
Правильно, поэтому, если вы действительно используете интерфейсы, вы, вероятно, захотите использовать их правильно и последовательно. Другими словами, вы больше не хотите объявлять ExtraNode/ExtraElement/и т. Д. как их конкретные типы - все ваши переменные всегда будут введены в интерфейс. Затем, поскольку «ExtraNode» будет иметь тип IExtraNode, вы можете сделать: ExtraNode = someExtraElement ?? someExtraNode. –