2013-08-16 12 views
7

Angenommen, ich verwende eine external package for storing graphs. Ein BidirectionalGraph nimmt zwei Vorlagen: eine Ecke und einen Randtyp:Erlaube, dass Vorlagen abgeleitet werden

var graph = new BidirectionalGraph<Vertex, Edge<Vertex>>(); 

Leider ist dieses Diagramm Paket nicht zulässt, dass, um die Kanten zu bekommen strahl in eine Ecke in einer einzigen Zeile. Stattdessen müssen Sie eine IEnumerable angeben, die mit den Ergebnissen ausgefüllt wird. Dies kann einen guten Codierungsrhythmus stören, indem Tasks wie "Schleife durch alle Knoten, die Nachfolger des Vertex x sind, viel zu viel Code benötigen.

Ich wollte von .NET-Erweiterungen verwenden, um eine einzeilige Lösung der Graph Klasse hinzuzufügen:

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; 
    } 
} 

Aber wenn ich graph.IncomingEdges(vertex) nennen, aus irgendeinem Grunde C# (.NET Version 4.5) kann nicht geschlossen werden die Template-Argumente, also muss ich sagen:

graph.IncomingEdges<GraphThatInheritsFromBidirectionalGraph<VertexType,EdgeType>,VertexType,EdgeType>(vertex). Nicht wirklich eine große Verbesserung.

Zuerst, warum können die Schablonentypen nicht geschätzt werden? Ich habe das Gefühl, dass es mit Vererbung zu tun hat, aber verstehe nicht. Ich bin es gewohnt, C++ zu verwenden, und aus irgendeinem Grund glaube ich, dass gcc die Vorlagentypen ableiten könnte.

Zweite wenn diese nicht verhindert werden kann, ist die richtige Design-Wahl eine Grafik-Klasse für den tatsächlichen Gebrauch zu machen, die von BidirectionalGraph erbt? Es scheint eine Verschwendung zu sein, die Konstruktoren neu schreiben zu müssen, aber ich bin mir sicher, Sie würden zustimmen, dass das Aufrufen der Methode mit expliziten Vorlagentypen unelegant ist.

EDIT:

Strangely die äquivalente Spezifikation (unten) tut erlauben automatische Inferenz von Templat-Typen. Also, obwohl es mein anfängliches Problem löst (das Hinzufügen dieser Funktionalität zum Graphen), würde ich immer noch gerne verstehen.

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

Was ist der Compilerfehler? Ich versuche, dies zu reproduzieren, ohne die Grafik Bibliothek herunterladen .. aber bisher versage ich :( –

+0

@SimonWithehead Es heißt "Fehler 1 'MyDerivedGraph' enthält keine Definition für 'IncomingEdges' und keine Erweiterungsmethode 'IncomingEdges 'könnte ein erstes Argument vom Typ' MyDerivedGraph 'gefunden werden (fehlt eine using-Direktive oder eine Assembly-Referenz?) ", aber wenn ich die Template-Typen manuell spezifiziere, kompiliert und läuft es gut. (EDIT: Resharper schlägt vor, < > versuche mir zu helfen, Templates manuell einzufügen – user

Antwort

1

Die erste Version der Extension-Methode ist in der Lage TGraphType und TVertex zu schließen, aber nicht TEgde, da sie die TEdge vom Typ Einschränkung Folgern erfordern würden:

where TGraphSubtype : BidirectionalGraph<TVertex, TEdge> 

die C# Compiler tun nicht (Es leitet keine generischen Typparameter von Typbeschränkungen ab). Ich weiß ehrlich gesagt nicht, ob es einen technischen Grund dafür gibt oder einfach nicht umgesetzt wurde.

Ihre aktualisierte Version, auf der anderen Seite enthält BidirectionalGraph<TVertex, TEdge> als Parameter, so zum Beispiel, wenn Sie die Erweiterung Methode für eine Klasse nennen wie:

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

der Compiler in der Lage ist, den Typ zu untersuchen AGraph und Beachten Sie, dass in seiner Vererbungshierarchie ein eindeutiger Typ BidirectionalGraph<AVertex, AnEdge> vorhanden ist, sodass er auf TVertex und TEdge schließen kann.

Beachten Sie, dass, wenn der Parameter Typ IGraph<TVertex, TEdge> waren (statt BidirectionalGraph<TVertex, TEdge>) und AGraph implementiert mehrere konstruierten Typen dieser generischen Schnittstelle, zum Beispiel:

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

dann Inferenz gibt erneut fehlschlagen würde, weil es nicht sagen kann, wenn zum Beispiel TVertexAVertex oder AnotherVertex ist.

Verwandte Themen