Я сталкиваюсь с ситуацией, где у меня есть зависимые объекты, и я хотел бы смочь удалить объект и все ссылки на него.
Скажите, что у меня есть структура объекта как код ниже с типом Ответвления который ссылки два Узла.
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;
}
Если я удаляю Узел из списка Узлов в классе Графика, все еще возможно, что один или несколько объектов Ответвления все еще содержат ссылку на удаленный Узел, таким образом сохраняя его в памяти, тогда как действительно то, что я вполне хотел бы, должно будет установить любые ссылки на удаленный Узел, чтобы аннулировать и впустить удар сборки "мусора".
Кроме перечисления посредством каждого Ответвления и проверки каждой ссылки Узла последовательно, там какие-либо умные мысли о том, как я удаляю ссылки на Узел в каждом экземпляре Ответвления И действительно каком-либо другом классе, которые ссылаются на удаленный Узел?
Измените свой узел, включив в него список ветвей, в которых он находится:
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 не нужен список узлов или ветвей, все, что ему нужно, - это один корневой узел. Когда вы удаляете узел, вы удаляете с него все ответвления. Очевидно, вы инкапсулируете все методы для добавления и удаления узлов и ветвей, чтобы внешний код не мог нарушить структуру.
Если вы на самом деле не храните какие-либо данные в Branch (чаще называемом Edge), они вам вообще не нужны. Узлы могут просто поддерживать список других узлов, с которых они связаны и с которыми они связаны.
Для этого нет встроенной функции языка C # (вы не можете отслеживать назначения). Вам нужно будет где-то отслеживать все ссылки и обновлять их, как только вы назначите для них новую ссылку. Очень общая идея состоит в том, чтобы предоставить событие Removed
в самом узле
и инициировать событие, когда объект должен быть оставлен. Каждый раз, когда вы хотите сохранить новую ссылку на узел
, вы должны подписаться на событие с соответствующим делегатом, который обнуляет ссылку на этот объект.
Конечно, если вы делаете это с набором ранее известных типов, которые определенным образом ссылаются на узел, могут быть более простые и эффективные способы выполнения задачи.
Некоторому классу, содержащему ссылку на узел, не понравится, если какой-то механизм просто удалит эту ссылку. И нет, другого выхода нет. Вам нужно выполнить итерацию и вручную установить для них значение null. Но если Node представляет собой ограниченный или ресурсоемкий ресурс, вам следует подумать об управлении доступом к нему лучше, возможно, из центра.
Я рекомендую сделать так, чтобы только ваш график знал о ветвях и узлах. Таким образом, вы можете контролировать доступ и быть уверенным, что знаете, как сделать недействительными все свои собственные ссылки. Если вам нужно предоставить доступ к пользовательским данным на узле, вы можете предоставить методы для итерации по вашей структуре, вместо того, чтобы предоставлять доступ к необработанной структуре. Вы можете встраивать информацию о пользователе в классы структуры с помощью универсальных шаблонов (т. Е. Определяемого пользователем свойства Tag для каждого узла и каждой ветви).
Вы, безусловно, можете запросить элементы вашей ветки на предмет ссылок на каждый узел, который вы удаляете, что-то вроде этого примера
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;
}
Который отлично подходит для удаления ссылок в вашем списке ветвей. Однако, как указывает Мердад, становится все труднее стереть все ссылки, если ссылки на ваш объект Node более многочисленны.
Попробуйте WeakReference в качестве оболочки для Node или Branch, списки будут содержать эти слабые ссылки.