从列表中删除项目以及对它们的所有引用

时间:2010-04-27 20:16:25

标签: c# list reference

我面临的情况是我有依赖对象,我希望能够删除一个对象及其所有引用。

假设我有一个类似下面代码的对象结构,其中Branch类型引用了两个节点。

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

如果我从Graph类的Nodes列表中删除一个Node,那么一个或多个Branch对象仍然可能包含对已删除节点的引用,从而将其保留在内存中,而我真的很喜欢它将对已删除节点的任何引用设置为null并让垃圾收集开始。

除了枚举每个分支并按顺序检查每个Node引用之外,是否有任何关于如何删除每个Branch实例中Node的引用以及引用已删除节点的任何其他类的明智想法?

6 个答案:

答案 0 :(得分:6)

没有内置的C#语言功能来实现(你无法真正跟踪作业)。您必须在某处跟踪所有引用,并在为其分配新引用时立即更新它。一般的想法是在Removed本身中提供Node事件,并在该对象应该被放弃时引发事件。每次要保留对Node的新引用时,您都会使用匹配的委托订阅该事件,该委托将对该对象的引用置零。 当然,如果您使用一组以特定方式引用节点的先前已知类型,则可能有更简单,更有效的方法来完成任务。

答案 1 :(得分: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
}

现在,您的Graph类不需要节点列表或分支列表,它只需要一个根节点。删除节点时,将删除所有分支。显然,您封装了所有添加和删除节点和分支的方法,因此外部代码不会破坏结构。

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

答案 2 :(得分:0)

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

答案 3 :(得分:0)

尝试将WeakReference作为Node或Branch的包装器,列表将包含这些弱引用。

答案 4 :(得分: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对象的引用更加丰富,则消除所有引用变得越来越困难。

答案 5 :(得分:0)

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