允许推断模板

use*_*ser 7 .net c# generics type-inference

假设我正在使用外部包来存储图形.BidirectionalGraph有两个模板:顶点和边缘类型:

var graph = new BidirectionalGraph<Vertex, Edge<Vertex>>();
Run Code Online (Sandbox Code Playgroud)

不幸的是,这个图形包不允许您将边缘辐射到一行中的顶点.相反,你必须提供一个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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是当我打电话时graph.IncomingEdges(vertex),由于某种原因,C#(.NET版本4.5)无法推断出模板参数,所以我不得不说:

graph.IncomingEdges<GraphThatInheritsFromBidirectionalGraph<VertexType,EdgeType>,VertexType,EdgeType>(vertex).并不是一个很大的进步.

首先,为什么不能估计模板类型?我觉得它与继承有关,但不明白.我习惯使用C++,并且出于某种原因认为gcc可以推断出模板类型.

其次,如果无法避免这种情况,那么为实际使用制作图形类是正确的设计选择,它继承自BidirectionalGraph?重写构造函数似乎是浪费,但我相信你会同意使用显式模板类型调用方法是不优雅的.

编辑:

奇怪的是,等效规范(下面)确实允许自动推断模板类型.所以,即使它解决了我的初始问题(将此功能添加到图表中),我仍然非常想了解.

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;
        }
}
Run Code Online (Sandbox Code Playgroud)

Ere*_*mez 1

扩展方法的第一个版本能够推断出TGraphTypeandTVertex但不能推断出TEgde,因为它需要TEdge从类型约束推断出 :

where TGraphSubtype : BidirectionalGraph<TVertex, TEdge>
Run Code Online (Sandbox Code Playgroud)

C# 编译器不会这样做(它不会从类型约束推断泛型类型参数)。老实说,我不知道这背后是否有技术原因,或者只是没有实施。

另一方面,您的更新版本包含BidirectionalGraph<TVertex, TEdge>参数,因此例如当您在类上调用扩展方法时,例如:

class AGraph: BidirectionalGraph<AVertex, AnEdge> { ... }
...
var aGraph = new AGraph();
aGraph.IncomingEdges(vertex);
Run Code Online (Sandbox Code Playgroud)

编译器能够检查类型AGraph并发现其继承层次结构中存在唯一类型BidirectionalGraph<AVertex, AnEdge>,因此能够推断出TVertexTEdge

请注意,如果参数类型是IGraph<TVertex, TEdge>(而不是BidirectionalGraph<TVertex, TEdge>)并且AGraph实现了该通用接口的多个构造类型,例如:

class AGraph: IGraph<AVertex, AnEdge>, 
              IGraph<AnotherVertex, AnotherEdge> { ... }
Run Code Online (Sandbox Code Playgroud)

那么类型推断将再次失败,因为它无法判断是否TVertex是 isAVertexAnotherVertex