我面临的情况是我有依赖对象,我希望能够删除一个对象及其所有引用。
假设我有一个类似下面代码的对象结构,其中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的引用以及引用已删除节点的任何其他类的明智想法?
答案 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”属性)。