Parameterizing a Generic Interface in a Class Declaration

So I needed to do a search using vertices and edges that are already computed in another part of the code (I see this part as a black box).

So, I have my graph with a list of vertices and edges:

class Graph {
    List<Vertex> vertices;
    List<Edge> edges;
}

      

I decided to do a generic search implementation and created a wrapper for the vertices:

class Node<T> {...}

      

and created an interface for the edges so that I can use them in a search:

interface ISearchLink<T> {...}

      

as a result, the header of the search method looks like this:

public static List<Node<T>> Search(List<Node<T>> nodes, List<ISearchLink<T>> links);

      

now, because the edges are already using the type that I need, and to make it compatible with the other part, I changed the declaration of the Edge class to look like (and implement interface methods):

class Edge : ISearchLink<Vertex> {...}

      

so now when i call search it says i have invalid arguments

List<Node<T>> table = search(vertices, edges);

      

which seems to indicate that Edge's declaration is invalid (although I have no complaints from VS). Is this expression invalid, and if so why is there no error? And if this is not invalid, then what is the problem? (VS can't seem to convert the "Edge" list to the "ISearchLink" Vertex "list)

edit: errors in specific case:

The best overloaded method match for Node<Vertex>.search(System.Collections.Generic.List<Vertex>, System.Collections.Generic.List<ISearchLink<Vertex>>)' has some invalid arguments

      

and

cannot convert from 'System.Collections.Generic.List<Edge>' to 'System.Collections.Generic.List<ISearchLink<Vertex>>'

      

+3


source to share


2 answers


The problem is that your search method accepts lists:

public static List<Node<T>> Search<T>(List<Node<T>> nodes, List<ISearchLink<T>> links)

      

When you say "VS can't seem to convert List<Edge>

to List<ISearchLink<Vertex>>

" because a List<Edge>

really isn't List<ISearchLink<Vertex>>

. VS shouldn't be converting like it is for you, because the List<T>

invariant in T

.

By saying that your method must accept List

s, you are telling the caller that you can access and use the items in that collection (which means that the type you expect as a parameter must be assigned from the caller type), but you can also insert something into this collection (this means that the type provided by the caller must be assignable from the type you expect)! This blocks the caller to provide exactly the expected type.



IEnumerable<T>

, on the other hand, is covariant in T

. You cannot insert new items into IEnumerable<T>

; you can only get everything. This means that the type you are expecting as a parameter must be assigned from the type that the caller provides that matches the situation you are expecting ISearchLink<T>

, which is assigned from Edge. But it is fine if the type provided by the caller cannot be assigned from the type expected as a parameter, because there will be no assignments in that direction.

So change the function to signature

public static List<Node<T>> Search<T>(List<Node<T>> nodes, IEnumerable<ISearchLink<T>> links)

      

Now VS happily converts List<Edge>

to IEnumerable<ISearchLink<Vertex>>

because it knows you are going to pull stuff from the list and not do things like pasting MyEvilSearchLink<Vertex>>

into what it really is List<Edge>

.

+1


source


The correct function header would be

public static List<Node<T>> Search<T>(List<Node<T>> nodes, List<ISearchLink<T>> links)
{

}

      



Don't forget <T>

afterSearch

0


source







All Articles