2013-08-16 13 views
7

Dire che sto usando un external package for storing graphs. Un BidirectionalGraph prende due modelli: un vertice e un tipo di bordo:Consenti modelli da dedurre

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

Purtroppo, questo pacchetto grafico non consentono di ottenere i bordi radianti in un vertice in una singola linea. Invece, devi fornire uno IEnumerable, che verrà compilato con i risultati. Questo può disturbare un buon ritmo di codifica rendendo compiti come "loop through tutti i vertici che sono successori del vertice x" prendere troppo codice.

ho voluto utilizzare le estensioni di .NET per aggiungere una soluzione di una riga alla classe grafico:

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

Ma quando chiamo graph.IncomingEdges(vertex), per qualche motivo C# (.NET versione 4.5) non può inferire gli argomenti del modello, quindi devo dire:

graph.IncomingEdges<GraphThatInheritsFromBidirectionalGraph<VertexType,EdgeType>,VertexType,EdgeType>(vertex). Non è davvero un grande miglioramento.

Primo, perché non è possibile stimare i tipi di modello? Ho la sensazione che abbia a che fare con l'ereditarietà, ma non capisco. Sono abituato a usare C++ e, per qualche ragione, ritengo che gcc possa dedurre i tipi di template.

Secondo, se questo non può essere impedito, è la scelta di progettazione corretta per rendere una classe di grafico per l'uso effettivo, che eredita da BidirectionalGraph? Sembra uno spreco dover riscrivere i costruttori, ma sono sicuro che concorderesti che chiamare il metodo con tipi di template espliciti sia inelegante.

EDIT:

Stranamente, la specifica equivalente (sotto) fa permettono inferire automaticamente tipi di modello. Quindi, anche se risolve il mio problema iniziale (aggiungendo questa funzionalità al grafico), mi piacerebbe davvero capire.

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

Qual è l'errore del compilatore? Sto cercando di ri-produrre questo senza scaricare la libreria di grafici .. ma finora sto fallendo :( –

+0

@SimonWhitehead Dice "Errore 1 'MyDerivedGraph' non contiene una definizione per 'IncomingEdges' e nessun metodo di estensione 'IncomingEdges 'accettando un primo argomento di tipo' MyDerivedGraph 'potrebbe essere trovato (ti manca una direttiva using o un riferimento di assembly?) ", ma quando specifichi manualmente i tipi di template, esso compila e gira bene. (EDIT: Resharper suggerisce l'inserimento < >, cercando di aiutarmi a inserire manualmente i modelli) – user

risposta

1

La prima versione del metodo di estensione è in grado di dedurre TGraphType e TVertex ma non TEgde, in quanto richiederebbe inferire il TEdge dal vincolo tipo:

where TGraphSubtype : BidirectionalGraph<TVertex, TEdge> 

quale compilatore C# non lo fa (Non deduce parametri di tipo generico da vincoli di tipo). Onestamente non so se c'è una ragione tecnica alla base di questo o semplicemente non è stata implementata.

La versione aggiornata, d'altra parte, include BidirectionalGraph<TVertex, TEdge> come parametro, così per esempio quando si chiama il metodo di estensione su una classe come:

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

il compilatore è in grado di esaminare il tipo AGraph e vedere che esiste un tipo unico BidirectionalGraph<AVertex, AnEdge> nella sua gerarchia di ereditarietà, quindi è in grado di dedurre TVertex e TEdge.

Nota che se il tipo di parametro fosse IGraph<TVertex, TEdge> (invece di BidirectionalGraph<TVertex, TEdge>) e AGraph attuate molteplici costruito tipi di interfaccia generica che, ad esempio:

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

quindi digitare l'inferenza non riuscirebbe ancora una volta, perché non può dire se, ad esempio, TVertex è AVertex o AnotherVertex.

Problemi correlati