【问题标题】:Allow templates to be inferred允许推断模板
【发布时间】:2013-08-16 11:59:22
【问题描述】:

假设我使用的是external package for storing graphs。 BidirectionalGraph 有两个模板:一个顶点和一个边类型:

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&lt;GraphThatInheritsFromBidirectionalGraph&lt;VertexType,EdgeType&gt;,VertexType,EdgeType&gt;(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;
        }
}

【问题讨论】:

  • 什么是编译器错误?我试图在不下载图形库的情况下重新生成它.. 但到目前为止我失败了:(
  • @SimonWhitehead 它说“错误 1 ​​'MyDerivedGraph' 不包含 'IncomingEdges' 的定义,并且找不到接受类型为 'MyDerivedGraph' 的第一个参数的扩展方法 'IncomingEdges'(你错过了吗? using 指令或程序集引用?)”,但是当我手动指定模板类型时,它编译并运行良好。 (编辑:Resharper 建议插入 ,试图帮助我手动放入模板)

标签: c# .net generics type-inference


【解决方案1】:

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

where TGraphSubtype : BidirectionalGraph<TVertex, TEdge>

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

另一方面,您的更新版本包含BidirectionalGraph&lt;TVertex, TEdge&gt; 作为参数,例如,当您在类上调用扩展方法时:

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

编译器能够检查类型AGraph 并看到在其继承层次结构中有一个唯一类型BidirectionalGraph&lt;AVertex, AnEdge&gt;,因此它能够推断出TVertexTEdge

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

class AGraph: IGraph<AVertex, AnEdge>, 
              IGraph<AnotherVertex, AnotherEdge> { ... }

然后类型推断将再次失败,因为它无法判断TVertexAVertex 还是AnotherVertex

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-03
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    • 1970-01-01
    • 1970-01-01
    • 2022-12-02
    相关资源
    最近更新 更多