1

I am trying to implement some graph searching algorithms in .NET for fun and personal education. For my implementation, I chose to start with a Node class that implemented the following interface:

public interface INode<T>
{
    T Data { get; }

    IDictionary<INode<T>, int> Neighbors { get; set; }
}

The node contains some Data of type T, as well as a dictionary of nodes that it shares an edge with along with their integer distance. I then thought that I could create an abstract Node class:

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

The above doesn't work, however, since neighbors doesn't match Neighbors. I would like whatever parameters are in Node's constructor to include an IDictionary of that specific type of Node and not just something that implements INode. For example, I might later create a concrete class called GraphNode, and I want to be sure that only GraphNodes are used in the constructor.

To solve this, I could simply take the IDictionary Neighbors out of INode and put it into the abstract Node class. This could limit my ability to test the class later on though using a framework like FakeItEasy, and I'm not sure what other implications it might have down the line.

I would appreciate some suggestions on how to generally approach this problem. If there is no best solution, then what are some pros and cons of various solutions?

losmescaleros
  • 498
  • 7
  • 12

1 Answers1

2

Based on the given code, there are two things that you can do to make this compile.

First, the code also doesn't compile because INode<T> is not fully implemented. Your interface defines a set method for Neighbors, so your set will have to be public, or you will have to explicitly implement that property.

Second, presuming you really want to restrict your constructor to take neighbors as a dictionary keyed on the Node<T> class, and not the interface, the quickest thing you can do to load up this.Neighbors is change the line to

this.Neighbors = neighbors.ToDictionary(
    neighborDistance => (INode<T>)neighborDistance.Key,
    neighborDistance => neighborDistance.Value
);

Something like this must be done because generic IDictionary is not covariant.

Community
  • 1
  • 1
maxwellb
  • 13,366
  • 2
  • 25
  • 35