允许推断模板
本文关键字:许推断 | 更新日期: 2023-09-27 18:27:53
假设我正在使用外部包来存储图形。双向图采用两个模板:顶点和边类型:
var graph = new BidirectionalGraph<Vertex, Edge<Vertex>>();
遗憾的是,此图形包不允许您将边辐射到单行中的顶点。相反,您必须提供一个 IEnumerable
,它将填充结果。这可能会破坏良好的编码节奏,使诸如"遍历顶点x
的后继者的所有顶点"之类的任务占用太多代码。
我想用.NET的扩展,用于向图形类添加单行解决方案:
public static class GraphExtensions
{
public static IEnumerable<TEdge> IncomingEdges<TGraphSubtype, TVertex, TEdge>(this TGraphSubtype graph, TVertex n)
where TGraphSubtype : BidirectionalGraph<TVertex, TEdge>
where TEdge : IEdge<TVertex>
{
IEnumerable<TEdge> inputEdgesForVertex;
graph.TryGetInEdges(n, out inputEdgesForVertex);
return inputEdgesForVertex;
}
}
但是当我调用graph.IncomingEdges(vertex)
时,由于某种原因C#(.NET 版本 4.5(无法推断模板参数,所以我不得不说:
graph.IncomingEdges<GraphThatInheritsFromBidirectionalGraph<VertexType,EdgeType>,VertexType,EdgeType>(vertex)
.并不是一个很大的改进。
首先,为什么无法估计模板类型?我有一种感觉,这与继承有关,但不明白。我习惯于使用C++,并且出于某种原因觉得 gcc 可以推断模板类型。
其次,如果无法阻止这种情况,那么正确的设计选择是制作一个实际使用的图类,它继承自双向图?必须重写构造函数似乎是一种浪费,但我相信您会同意使用显式模板类型调用该方法是不优雅的。
编辑:
奇怪的是,等效规范(如下(确实允许自动推断模板类型。因此,即使它解决了我最初的问题(将此功能添加到图形中(,我仍然非常想了解。
public static class GraphExtensions
{
public static IEnumerable<TEdge> IncomingEdges<TVertex, TEdge>(this BidirectionalGraph<TVertex,TEdge> graph, TVertex n)
where TEdge : IEdge<TVertex>
{
IEnumerable<TEdge> inputEdgesForVertex;
graph.TryGetInEdges(n, out inputEdgesForVertex);
return inputEdgesForVertex;
}
}
方法的第一个版本能够推断TGraphType
和TVertex
,但不能推断TEgde
,因为它需要从类型约束推断TEdge
:
where TGraphSubtype : BidirectionalGraph<TVertex, TEdge>
C# 编译器不执行的操作(它不会从类型约束推断泛型类型参数(。老实说,我不知道这背后是否有技术原因,或者只是没有实施。
另一方面,更新后的版本包含BidirectionalGraph<TVertex, TEdge>
作为参数,例如,当您在类上调用扩展方法时,例如:
class AGraph: BidirectionalGraph<AVertex, AnEdge> { ... }
...
var aGraph = new AGraph();
aGraph.IncomingEdges(vertex);
编译器能够检查类型AGraph
,并看到其继承层次结构中有一个唯一的类型BidirectionalGraph<AVertex, AnEdge>
,因此它能够推断TVertex
和TEdge
。
请注意,如果参数类型是IGraph<TVertex, TEdge>
(而不是BidirectionalGraph<TVertex, TEdge>
(并且AGraph
实现了该泛型接口的多个构造类型,例如:
class AGraph: IGraph<AVertex, AnEdge>,
IGraph<AnotherVertex, AnotherEdge> { ... }
然后类型推断将再次失败,因为它无法判断TVertex
是AVertex
还是AnotherVertex
。