2010-04-27 60 views
7

我面临的情况是,我有依赖对象,我希望能够删除一个对象和所有对它的引用。删除列表中的项目和所有对它们的引用

说我有一个像下面的代码的对象结构,引用两个节点的分支类型。

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

如果我删除从图形类的节点列表中的节点,它仍然是有可能的一个或多个分公司的对象仍然包含已删除节点的引用,因此其保留在内存中,而真的是我将相当喜欢将设置为删除节点的任何引用为空,并让垃圾回收踢入。

除了枚举每个分支和检查每个节点参考顺序,有没有关于如何删除引用到每个分支实例中的节点,以及其他任何引用已删除节点的类?

+1

你实际上是否在分支上存储任何数据?如果不是的话,你可以完全摆脱这个类,只是在Node类中存储相关的节点。 – 2010-04-27 20:48:10

+0

嗨,是的,我正在存储一些其他数据,上面的数据结构只是一个简单的例子来显示我的实际模型的引用。 – LiamV 2010-04-27 20:51:59

回答

1

更改您的节点,包括它在新的分支:

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 
} 

现在您的图表类不需要节点或分支的列表,它需要的只是一个根节点。当你删除一个节点时,你可以删除所有的分支。很明显,你封装了所有的方法来添加和删除节点和分支,所以外部代码不能破坏结构。

如果您实际上没有在Branch上存储任何数据(通常称为Edge),则根本不需要它。节点可以维护它们连接的其他节点的列表。

+0

你是对的,我不需要基于我给出的信息的节点或分支的列表,但是在那里是你可能不会考虑的其他因素。 例如,这些数据实际上将存储在数据库中,因此将每种类型的列表映射到数据库表是更合适的。 – LiamV 2010-04-27 20:55:53

+0

该结构可以*很容易*映射到数据库:节点的表格,边缘的表格,它们之间的FK关系。它是100%的关系模型。 EF 4可以处理所有延迟加载边缘和节点的问题,而无需额外的工作。将数据库导入实体数据模型时,您可以自动获取Node.Edges。事实上,它也会使删除变得容易,当你删除一个Edge时,它可以自动从每个节点中删除它。 – 2010-04-27 21:31:41

0

某些持有对Node的引用的类不会喜欢它,如果某种机制只是删除了这个引用。不,没有其他办法。您必须迭代并将它们手动设置为null。但是,如果Node代表有限或内存密集的资源,则应该考虑更好地管理对它的访问,也许在一个中心位置。

+0

非常感谢您的回复,这无疑给了我一些想法。我想我会沿着Hightechrider建议的路线走下去,直到遇到一些问题。出于这个原因,我已经接受了他的答案。 – LiamV 2010-04-28 19:38:38

6

有没有内置的C#语言功能来配合(你不能真的跟踪任务)。您必须随时跟踪所有引用,并在您为其分配新引用后立即对其进行更新。一个非常普遍的想法是在Node本身提供一个Removed事件,并在应该放弃对象时引发该事件。每当您想要坚持对Node的新引用时,您都会使用匹配的委托来订阅事件,该委托会将该对象的引用归零。 当然,如果您使用一组以特定方式引用节点的先前已知类型,可能会有更简单和更高效的方法来完成此任务。

0

尝试WeakReference作为节点或分支的包装,列表将包含这些弱引用。

+1

'WeakReference'将消除垃圾收集问题,但如果您需要在删除节点后立即在不同位置适当地更新数据结构,它将不会解决问题。 – 2010-04-27 20:26:10

+0

所以实现事件OnAdded,OnRemoved和保留后向引用 - 所以每个节点将知道它所在的分支。 – 2010-04-27 20:43:27

0

你当然可以查询,你删除,这样的例子

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

这很好的去除引用你的分支机构名单。但是,就像Mehrdad指出的那样,如果对Node对象的引用更多,消除所有引用变得越来越困难。

0

我建议这样做只有你的Graph知道分支和节点。通过这种方式,您可以控制访问权限,并确保您知道如何使所有自己的引用无效。如果您需要在Node上提供对用户数据的访问权限,则可以提供遍历结构的方法,而不是访问原始结构。您可以通过泛型将用户信息嵌入到结构类中(即用户定义的每个节点和每个分支的'Tag'属性)。