2013-08-16 8 views
7

Powiedz, że używam external package for storing graphs. BidirectionalGraph trwa dwa szablony: wierzchołek i typ krawędzi:Zezwalaj na szablony, które można wywnioskować

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

Niestety, pakiet ten wykres nie pozwalają uzyskać krawędzie promieniujące do wierzchołka w jednym wierszu. Zamiast tego musisz podać numer IEnumerable, który zostanie zapełniony wynikami. Może to zakłócić dobry rytm kodowania, powodując, że zadania takie jak "przechodzą przez wszystkie wierzchołki będące następcami wierzchołka x" pobierają zbyt dużo kodu.

chciałem użyć rozszerzenia .NET, aby dodać rozwiązanie jednego wiersza do klasy wykresie:

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

Ale gdy zgłoszę graph.IncomingEdges(vertex), z jakiegoś powodu, C# (.NET w wersji 4.5) nie można wywnioskować, argumenty szablonu, więc muszę powiedzieć:

graph.IncomingEdges<GraphThatInheritsFromBidirectionalGraph<VertexType,EdgeType>,VertexType,EdgeType>(vertex). Naprawdę nie jest to doskonała poprawa.

Po pierwsze, dlaczego nie można oszacować typów szablonów? Mam wrażenie, że ma to związek z dziedziczeniem, ale nie rozumiem. Jestem przyzwyczajony do używania C++ iz jakiegoś powodu czuję, że gcc może wnioskować o typach szablonów.

Po drugie, jeśli nie można tego uniknąć, czy jest to właściwy wybór projektu, aby utworzyć klasę wykresów rzeczywistych, która dziedziczy po BidirectionalGraph? Wydaje się, że trzeba przerobić konstruktorów na straty, ale jestem pewien, że zgodziłbyś się, że wywołanie metody z jawnymi typami szablonów jest nieeleganckie.

Edycja:

dziwne, co odpowiada specyfikacji (poniżej) nie umożliwić automatyczne wnioskowania rodzaju szablonów. Tak więc, mimo że rozwiązuje to mój początkowy problem (dodając tę ​​funkcję do wykresu), nadal chciałbym to zrozumieć.

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

Co to jest błąd kompilatora? Próbuję ponownie produkować to bez pobierania biblioteki graficznej .. ale do tej pory zawodzę :( –

+0

@SimonWhitehead Mówi "Błąd 1" MyDerivedGraph "nie zawiera definicji" IncomingEdges "i nie ma metody rozszerzenia" IncomingEdges " "można znaleźć pierwszy argument typu" MyDerivedGraph "(czy brakuje instrukcji użycia lub odniesienia do zestawu?)", ale kiedy ręcznie określam typy szablonów, kompiluje się i działa poprawnie. (EDIT: Resharper sugeruje wstawianie < >, próbuję pomóc mi ręcznie wstawić szablony) – user

Odpowiedz

1

Pierwsza wersja metodę rozszerzenia jest w stanie wywnioskować TGraphType i TVertex ale nie TEgde, gdyż wymagałoby to wywodząc się TEdge z ograniczeń typu:

where TGraphSubtype : BidirectionalGraph<TVertex, TEdge> 

który kompilator C# nie robi (nie określa typowych parametrów typu z ograniczeń typu). Szczerze mówiąc, nie wiem, czy istnieje ku temu powód techniczny, czy po prostu nie został on wdrożony.

Twoja wersja zaktualizowana, z drugiej strony, zawiera BidirectionalGraph<TVertex, TEdge> jako parametr, więc na przykład podczas wywoływania metody rozszerzenie na klasę jak:

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

kompilator jest w stanie zbadać rodzaj AGraph i zobacz, że istnieje unikalny typ BidirectionalGraph<AVertex, AnEdge> w jego hierarchii dziedziczenia, więc jest on w stanie wywnioskować TVertex i TEdge.

Zauważ, że jeśli typ parametru były IGraph<TVertex, TEdge> (zamiast BidirectionalGraph<TVertex, TEdge>) i AGraph realizowane wielokrotne skonstruowane typy tego rodzajowego interfejsu, np:

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

następnie wpisać wnioskowanie nie powiedzie się ponownie, ponieważ nie można powiedzieć jeśli, na przykład, TVertex jest AVertex lub AnotherVertex.