Я пытаюсь реализовать некоторые алгоритмы поиска графов в.NET для развлечения и личного обучения. Для моей реализации я решил начать с класса Node, который реализовал следующий интерфейс:
public interface INode<T>
{
T Data { get; }
IDictionary<INode<T>, int> Neighbors { get; set; }
}
Узел содержит некоторые Data
типа T, а также словарь узлов, в котором он разделяет ребро вместе с их целым расстоянием. Затем я подумал, что могу создать абстрактный класс Node
:
public abstract class Node<T> : INode<T>
{
public T Data { get; private set; }
public IDictionary<INode<T>, int> Neighbors { get; private set; }
public Node(T data, IDictionary<Node<T>, int> neighbors)
{
this.Data = data;
this.Neighbors = neighbors;
}
}
Вышеприведенное не работает, однако, поскольку neighbors
не соответствуют Neighbors
. Я хотел бы, чтобы любые параметры в конструкторе Node
включали IDictionary
этого конкретного типа Node
а не только то, что реализует INode
. Например, я могу позже создать конкретный класс под названием GraphNode, и я хочу быть уверенным, что в конструкторе используются только GraphNodes.
Чтобы решить эту проблему, я мог просто вывести IDictionary Neighbors из INode и поместить ее в абстрактный класс Node. Это может ограничить мою способность тестировать класс позже, хотя с использованием фреймворка, такого как FakeItEasy, и я не уверен, какие другие последствия он мог бы иметь на линии.
Я был бы признателен за некоторые предложения о том, как вообще подходить к этой проблеме. Если нет лучшего решения, то каковы некоторые плюсы и минусы различных решений?
На основе данного кода есть две вещи, которые вы можете сделать, чтобы сделать эту компиляцию.
Во-первых, код также не компилируется, потому что INode<T>
не полностью реализован. Ваш интерфейс определяет метод set
для Neighbors
, поэтому ваш set
должен быть общедоступным или вам придется явно реализовать это свойство.
Во-вторых, предположим, что вы действительно хотите ограничить свой конструктор, чтобы neighbors
в качестве словаря, который был введен в класс Node<T>
, а не интерфейс, самую быструю вещь, которую вы можете сделать, чтобы загрузить это. this.Neighbors
меняют линию на
this.Neighbors = neighbors.ToDictionary(
neighborDistance => (INode<T>)neighborDistance.Key,
neighborDistance => neighborDistance.Value
);
Что-то вроде этого должно быть сделано, потому что общий IDictionary
не является ковариантным.