2013-08-16 154 views
7

假设我正在使用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<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; 
     } 
} 
+0

什么是编译器错误?我试图重新生成这个没有下载图形库..但到目前为止,我失败:( –

+0

@SimonWhitehead它说“错误1'MyDerivedGraph'不包含'IncomingEdges'的定义和没有扩展方法'IncomingEdges '接受'MyDerivedGraph'类型的第一个参数可以找到(你是否缺少using指令或程序集引用?)“,但是当我手动指定模板类型时,它编译并运行正常。(编辑:resharper建议插入< >,试图帮助我手动输入模板) – user

回答

1

您的扩展方法的第一个版本能够推断TGraphTypeTVertex但不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>,因此它能够推断出TVertexTEdge

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

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

然后键入推断,因为它不能告诉会再次失败例如,如果TVertexAVertexAnotherVertex