Invalid Cast in C5.IPriorityQueueHandle

237 Views Asked by At

I'm having issues implementing the C5.IPriorityQueueHandle interface with the C5 IntervalHeap. I can use the heap fine with null handles, using the default DeleteMin(), etc., but I want to be able to update the priority by the handle later.

A simplified version of my code is below, together with the exception text:

Exception: An unhandled exception of type 'System.InvalidCastException' occurred in C5.dll

Additional information: Unable to cast object of type 'Handle`1[_8_Puzzle.Node]' to type 'Handle[_8_Puzzle.Node]'.

public class Node : IComparable<Node>
{
    public Board board;
    public Handle<Node> handle;
    public Node(Board b)
    {
        this.board = b;
        this.handle = new Handle<Node> (b.Id);
    }

    ...
}

public class Handle<Node> : C5.IPriorityQueueHandle<Node>
{
    private int id;

    public Handle(int id)
    {
        this.id = id;
    }
}

static void doWork(Node rootNode)
    {
        C5.IntervalHeap<Node> q = new C5.IntervalHeap<Node>();
        q.Add(rootNode); //works fine, handle is null

        ...

        Board child = getChild(rootNode);

        if (someConditionIsMet) {

            Node childNode = new Node(child);
            C5.IPriorityQueueHandle<Node> h = (C5.IPriorityQueueHandle<Node>)(childNode.handle);
            q.Add(ref h, childNode); //breaking line!

        }
    }
1

There are 1 best solutions below

0
On BEST ANSWER

You are using handles with the C5 library incorrectly.

From the C5 documentation for the handle parameter of the C5.IntervalHeap<T>.Add method (emphasis mine):

On output: a handle for the added item. On input: null for allocating a new handle, an invalid handle for reuse. A handle for reuse must be compatible with this priority queue, by being created by a priority queue of the same runtime type, but not necessarily the same priority queue object.

You are not passing in a handle created by a priority queue. You are passing in your own handles that you create in the Node class's constructor.

Don't create your own implementation of IPriorityQueueHandle<T>; rely instead on whatever handle objects you get back from C5. I would recommend you change the type of the handle field within Node to IPriorityQueueHandle<Node>, don't initialise it in the Node constructor, and change the call on the breaking line to

        q.Add(ref childNode.handle, childNode);

The line before, where you assign to the variable h, can be deleted, as can your Handle<T> class.