在类声明中参数化泛型接口

本文关键字:泛型接口 参数 声明 | 更新日期: 2023-09-27 18:06:05

因此,我需要使用已经在代码的另一部分(我将该部分视为黑盒)中计算的顶点和边来实现搜索。

我有了一个图,有一列顶点和边:

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

我决定为搜索做一个通用的实现,并为顶点创建一个包装器:

class Node<T> {...}

并为这些边创建了一个接口,这样我就可以在搜索中使用它们了:

interface ISearchLink<T> {...}
因此,搜索方法头看起来像这样:
public static List<Node<T>> Search(List<Node<T>> nodes, List<ISearchLink<T>> links);

现在,因为边缘已经使用了我想要的类型,为了与其他部分保持一致,我改变了边缘类声明,看起来像这样(并实现了接口方法):

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

所以现在当我调用搜索时,它说我有无效参数

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

似乎表明Edge声明无效(尽管我没有收到VS的投诉)。这个声明无效吗?如果无效,为什么没有错误?如果它不是无效的,那么问题是什么呢?(似乎VS不能转换列表«边缘»列表«ISearchLink«顶点»»)

编辑:具体错误如下:

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

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

在类声明中参数化泛型接口

问题是您的搜索方法正在接受列表:

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

当你说"似乎VS不能将List<Edge>转换为List<ISearchLink<Vertex>>"时,那是因为List<Edge> 真的不是 List<ISearchLink<Vertex>>。VS 不应该为你这样转换,因为List<T>T中是不变的。

通过说你的方法应该接受List s,你是在告诉调用者你可以访问和使用集合中的项(这意味着你期望作为参数的类型必须可以从调用者提供的类型中赋值),但你也可以在集合中插入一些东西(这意味着调用者提供的类型必须可以从你期望的类型中赋值)!这会将调用者锁定为提供所期望的类型。

IEnumerable<T>T中是协变的。你不能在IEnumerable<T>中插入新项目;你只能把东西弄出来。这意味着您期望作为参数的类型必须可以从调用者提供的类型中赋值——这对应于您期望ISearchLink<T>的情况,它可以从Edge中赋值。但是,如果调用者提供的类型不能从期望作为参数的类型中赋值,那也没关系,因为在那个方向上不会有任何赋值流动。

将函数改为签名

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

现在VS会很高兴地将List<Edge>转换为IEnumerable<ISearchLink<Vertex>>,因为它知道你只会把东西从列表中拉出来,而不是把MyEvilSearchLink<Vertex>>插入到实际的List<Edge>中。

正确的函数头应该是

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

别忘了Search后面的<T>