I am implementing fundamental data structures in C#. I have written a weighted graph in Java so my main motivation here is to sharpen my skills in C#. I have tested with various cases and there seems to be no logical issues, but I know the language could be better utilized.The Pathfinder method is not absolutely necessary, because the only difference with A* and Dijkstra is the Heuristic.  The reason I have it is two-fold. There are various optimizations of A* that I would like to implement in the future. Thus I want it to be isolated. I also want to master delegates, hence the use of Func.As always, I am open to any general or specific advice.WeightedGraphclass WeightedGraph<T>{    List<WeightedEdge<T>> edges;    List<Vertex<T>> vertices;    public List<WeightedEdge<T>> Edges { get { return edges; } }    public WeightedGraph(List<Vertex<T>> vertices, List<WeightedEdge<T>> edges)    {        this.vertices = vertices;        this.edges = edges;    }    public void AddEdge(WeightedEdge<T> newEdge)    {        edges.Add(newEdge);    }    public void RemoveEdge(WeightedEdge<T> edge)    {        edges.Remove(edge);    }    /// <summary>    /// Pathfinding algorithms available: Dijkstra and AStar    /// </summary>    public List<Vertex<T>> Pathfinder(Vertex<T> start, Vertex<T> end, string algorithm)    {        Func<Vertex<T>, Vertex<T>, List<Vertex<T>>> pathfinder;        if (algorithm == Dijkstra)        {            pathfinder = DijkstraSearch;        }        else if (algorithm == AStar)        {            pathfinder = AStarSearch;        }        else        {            throw new ArgumentException(Pathfinding algorithm not available.);        }        return pathfinder(start, end);    }    public List<Vertex<T>> DijkstraSearch(Vertex<T> start, Vertex<T> end)    {        Dictionary<Vertex<T>, Vertex<T>> parentMap = new Dictionary<Vertex<T>, Vertex<T>>();        PriorityQueue<Vertex<T>> priorityQueue = new PriorityQueue<Vertex<T>>();        InitializeCosts(start);        priorityQueue.Enqueue(start, start.Cost);        Vertex<T> current;        while (priorityQueue.Count > 0)        {            current = priorityQueue.Dequeue();            if (!current.IsVisited)            {                current.IsVisited = true;                if (current.Equals(end))                {                    break;                }                foreach (WeightedEdge<T> edge in current.Edges)                {                    Vertex<T> neighbor = edge.End;                    double newCost = current.Cost + edge.Weight;                    double neighborCost = neighbor.Cost;                    if (newCost < neighborCost)                    {                        neighbor.Cost = newCost;                        parentMap.Add(neighbor, current);                        double priority = newCost;                        priorityQueue.Enqueue(neighbor, priority);                    }                }            }        }        List<Vertex<T>> path = ReconstructPath(parentMap, start, end);        return path;    }    public List<Vertex<T>> AStarSearch(Vertex<T> start, Vertex<T> end)    {        Dictionary<Vertex<T>, Vertex<T>> parentMap = new Dictionary<Vertex<T>, Vertex<T>>();        PriorityQueue<Vertex<T>> priorityQueue = new PriorityQueue<Vertex<T>>();        InitializeCosts(start);        priorityQueue.Enqueue(start, start.Cost);        Vertex<T> current;        while (priorityQueue.Count > 0)        {            current = priorityQueue.Dequeue();            if (!current.IsVisited)            {                current.IsVisited = true;                if (current.Equals(end))                {                    break;                }                foreach (WeightedEdge<T> edge in current.Edges)                {                    Vertex<T> neighbor = edge.End;                    double newCost = current.Cost + edge.Weight;                    double neighborCost = neighbor.Cost;                    if (newCost < neighborCost)                    {                        neighbor.Cost = newCost;                        parentMap.Add(neighbor, current);                        double priority = newCost + Heuristic(neighbor, end);                        priorityQueue.Enqueue(neighbor, priority);                    }                }            }        }        List<Vertex<T>> path = ReconstructPath(parentMap, start, end);        return path;    }    public double Heuristic(Vertex<T> vertexA, Vertex<T> vertexB)    {        return vertexA.Location.DistanceTo(vertexB.Location);    }    public void InitializeCosts(Vertex<T> start)    {        foreach (Vertex<T> vertex in vertices)        {            vertex.Cost = int.MaxValue;        }        start.Cost = 0;    }    public List<Vertex<T>> ReconstructPath(Dictionary<Vertex<T>, Vertex<T>> parentMap, Vertex<T> start, Vertex<T> end)    {        List<Vertex<T>> path = new List<Vertex<T>>();        Vertex<T> current = end;        while (current != start)        {            path.Add(current);            current = parentMap[current];        }        path.Add(start);        path.Reverse();        return path;    }}Vertexclass Vertex<T>{    List<Vertex<T>> neighbors;    List<WeightedEdge<T>> edges;    T value;    public List<Vertex<T>> Neighbors { get { return neighbors; } }    public List<WeightedEdge<T>> Edges { get { return edges; } }    public Location Location { get; set; }    public T Value { get { return value; } set { this.value = value; } }    public bool IsVisited { get; set; }    public int NeighborsCount { get { return neighbors.Count; } }    public double Cost { get; set; }    public Vertex(T value)    {        this.value = value;        IsVisited = false;        neighbors = new List<Vertex<T>>();        edges = new List<WeightedEdge<T>>();    }    public Vertex(T value, List<Vertex<T>> neighbors)    {        this.value = value;        IsVisited = false;        this.neighbors = neighbors;    }    public void AddNeighbor(Vertex<T> vertex)    {        neighbors.Add(vertex);    }    public void AddEdge(WeightedEdge<T> edge)    {        edges.Add(edge);    }    public override string ToString()    {        StringBuilder allNeighbors = new StringBuilder();        allNeighbors.Append(value + : );        foreach (Vertex<T> neighbor in neighbors)        {            allNeighbors.Append(neighbor.value +   );        }        return allNeighbors.ToString();    }}WeightedEdgeclass WeightedEdge<T>{    int weight;    Vertex<T> start;    Vertex<T> end;    public int Weight { get { return weight; } }    public Vertex<T> Start { get { return start; } }    public Vertex<T> End { get { return end; } }    public WeightedEdge(Vertex<T> start, Vertex<T> end, int weight)    {        this.start = start;        this.end = end;        this.weight = weight;        start.AddNeighbor(end);        start.AddEdge(this);    }    public override string ToString()    {        return string.Format({0}--{1}-->{2}, start.Value, weight, end.Value);    }}
Weighted graph and pathfinding implementation in C#
c#;graph;pathfinding