2010-04-27 11 views
7

Sono di fronte a una situazione in cui sono presenti oggetti dipendenti e vorrei poter rimuovere un oggetto e tutti i riferimenti ad esso.Rimozione di elementi dagli elenchi e tutti i riferimenti a essi

Dire che ho una struttura di oggetti come il seguente codice, con un tipo Branch che fa riferimento a due nodi.

public class Node 
{ 
    // Has Some Data! 
} 

public class Branch 
{ 
    // Contains references to Nodes 
    public Node NodeA 
    public Node NodeB 
} 

public class Graph 
{ 
    public List<Node> Nodes; 
    public List<Branch> Branches; 
} 

Se rimuove un nodo dall'elenco Nodi nella classe Graph, è ancora possibile che uno o più oggetti Branch contiene ancora un riferimento al nodo rimosso, mantenendo così in memoria, mentre proprio quello che sarebbe abbastanza per impostare qualsiasi riferimento al Nodo rimosso su null e lasciare che la raccolta di dati inutili entri in gioco.

Altro che enumerare attraverso ogni Branch e controllare ogni riferimento Nodo in modo sequenziale, ci sono idee intelligenti su come rimuovo i riferimenti al nodo in ogni istanza di ramo E in effetti qualsiasi altra classe che fa riferimento al nodo rimosso?

+1

Si stanno effettivamente memorizzando dati sul ramo? Altrimenti puoi sbarazzarti completamente di quella classe e archiviare solo i nodi relativi nella classe Node. –

+0

Salve, Sì, sto memorizzando altri dati, la struttura dei dati sopra era solo un semplice esempio per mostrare dove sono i riferimenti del mio modello attuale. – LiamV

risposta

1

Cambia il nodo per includere un elenco delle filiali è su:

public class Node 
{ 
    // Has Some Data! 

    public List<Branch> BranchesIn; 
    public List<Branch> BranchesOut; // assuming this is a directed graph 

    public void Delete() 
    { 
     foreach (var branch in BranchesIn) 
     branch.NodeB.BranchesOut.Remove(branch); 

     foreach (var branch in BranchesOut) 
     branch.NodeA.BranchesIn.Remove(branch); 

     BranchesIn.Clear(); 
     BranchesOut.Clear(); 
    } 
} 

public class Branch 
{ 
    // Contains references to Nodes 
    public Node NodeA 
    public Node NodeB 
} 

Ora la classe Graph non ha bisogno di una lista di nodi o rami, tutto ciò che serve è un singolo nodo radice. Quando rimuovi un nodo, rimuovi tutti i rami da esso. Chiaramente incapsuli tutti i metodi per aggiungere e rimuovere nodi e rami in modo che il codice esterno non possa rompere la struttura.

Se non si memorizzano effettivamente dati sul ramo (in genere denominato Edge) non è necessario. I nodi possono semplicemente mantenere un elenco degli altri nodi da cui collegano da e verso.

+0

Hai ragione che non ho bisogno di un elenco di nodi o rami in base alle informazioni che ho dato, ma lì sono altri fattori che probabilmente non sapresti considerare. Ad esempio, questi dati verranno effettivamente memorizzati all'interno di un database, pertanto è più appropriato disporre di elenchi di ogni tipo, che si associano a una tabella di database. – LiamV

+0

Questa struttura può * facilmente * mappare su un database: tabella per Nodi, tabella per Bordi, relazioni FK tra di loro. È al 100% un modello relazionale. EF 4 è in grado di gestire tutti i problemi relativi al caricamento ponderato di bordi e nodi senza alcun lavoro aggiuntivo. Ottieni Node.Edges automaticamente, gratuitamente, quando importi il ​​database in un Entity Data Model. In effetti renderà facile anche l'eliminazione, quando rimuovi un Edge lo può rimuovere automaticamente da ogni Nodo. –

0

Qualche classe in possesso di un riferimento a un nodo non gli piacerebbe, se qualche meccanismo elimina solo questo riferimento. E no, non c'è altro modo. Devi iterare e impostarli su null manualmente. Ma se il Nodo rappresenta una risorsa intensiva limitata o memroy, dovresti considerare di gestirlo meglio, magari in un posto centrale.

+0

Grazie mille per tutte le tue risposte, mi ha sicuramente dato qualcosa a cui pensare. Penso che percorrerò la strada suggerita da Hightechrider, fino a quando non avrò trovato dei problemi. Per questo motivo ho accettato la sua risposta. – LiamV

6

Non esiste una funzione di linguaggio C# integrata per facilitarla (non è possibile tenere traccia dei compiti). Dovrai tenere traccia di tutti i riferimenti da qualche parte e aggiornarlo non appena si assegna un nuovo riferimento ad esso. Un'idea molto generale è quella di fornire un evento Removed nello stesso Node e generare l'evento quando l'oggetto deve essere abbandonato. Ogni volta che vuoi tenere un nuovo riferimento allo Node, ti iscrivi all'evento con un delegato corrispondente che annulli il riferimento a quell'oggetto. Ovviamente, se stai facendo questo con un set di tipi precedentemente noti che fanno riferimento al nodo in un modo specifico, ci possono essere modi più semplici ed efficienti per eseguire l'operazione.

0

Prova WeakReference come wrapper per Node o Branch, gli elenchi conterranno questi riferimenti deboli.

+1

'WeakReference' eliminerà il problema della garbage collection ma non affronterà il problema se è necessario aggiornare le strutture di dati in modo appropriato in luoghi diversi non appena viene rimosso un nodo. –

+0

quindi implementa gli eventi OnAdded, OnRemoved e mantiene i riferimenti all'indietro - in modo che ciascun nodo sappia di un Branch in cui si trova. –

0

È certamente possibile interrogare gli elementi filiali per i riferimenti a ciascun nodo che si sta rimuovendo, qualcosa di simile a questo esempio

class Branch 
{ 
    public Branch(Node nodeA, Node nodeB) { NodeA = nodeA; NodeB = nodeB; } 
    public Node NodeA { get; set; } 
    public Node NodeB { get; set; } 
} 

class Node 
{ 
    public Node(string name) { Name = name; } 
    public string Name { get; set; } 
} 

...

List<Node> nodes = new List<Node>() { new Node("Apple"), new Node("Banana") }; 
List<Branch> branches = new List<Branch>() { new Branch(nodes[0], nodes[1]), new Branch(nodes[1], nodes[0]) }; 

Node node = nodes[0]; 
nodes.Remove(node); 

var query = from branch in branches 
      where branch.NodeA == node || branch.NodeB == node 
      select branch; 

foreach (Branch branch in query) 
{ 
    if (branch.NodeA == node) 
     branch.NodeA = null; 
    if (branch.NodeB == node) // could just be 'else' if NodeA cannot equal NodeB 
     branch.NodeB = null; 
} 

che va bene per la rimozione di riferimenti a la tua lista di filiali. Tuttavia, come sottolinea Mehrdad, diventa sempre più difficile cancellare tutti i riferimenti se i riferimenti all'oggetto Node sono più prolifici.

0

Si consiglia di fare in modo che solo il grafico sia a conoscenza di rami e nodi. In questo modo puoi controllare l'accesso e assicurarti di sapere come invalidare tutti i tuoi riferimenti. Se è necessario fornire l'accesso ai dati dell'utente su un nodo, è possibile fornire metodi per iterare sulla struttura, piuttosto che concedere l'accesso alla struttura non elaborata. È possibile incorporare le informazioni utente nelle classi della struttura tramite generici (ovvero una proprietà 'Tag' definita dall'utente per ciascun nodo e ogni ramo).

Problemi correlati