Удаление объектов из списков и всех ссылок на них

Я сталкиваюсь с ситуацией, где у меня есть зависимые объекты, и я хотел бы смочь удалить объект и все ссылки на него.

Скажите, что у меня есть структура объекта как код ниже с типом Ответвления который ссылки два Узла.

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

Если я удаляю Узел из списка Узлов в классе Графика, все еще возможно, что один или несколько объектов Ответвления все еще содержат ссылку на удаленный Узел, таким образом сохраняя его в памяти, тогда как действительно то, что я вполне хотел бы, должно будет установить любые ссылки на удаленный Узел, чтобы аннулировать и впустить удар сборки "мусора".

Кроме перечисления посредством каждого Ответвления и проверки каждой ссылки Узла последовательно, там какие-либо умные мысли о том, как я удаляю ссылки на Узел в каждом экземпляре Ответвления И действительно каком-либо другом классе, которые ссылаются на удаленный Узел?

7
задан John Saunders 27 April 2010 в 20:51
поделиться

6 ответов

Измените свой узел, включив в него список ветвей, в которых он находится:

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), они вам вообще не нужны. Узлы могут просто поддерживать список других узлов, с которых они связаны и с которыми они связаны.

1
ответ дан 7 December 2019 в 07:41
поделиться

Для этого нет встроенной функции языка C # (вы не можете отслеживать назначения). Вам нужно будет где-то отслеживать все ссылки и обновлять их, как только вы назначите для них новую ссылку. Очень общая идея состоит в том, чтобы предоставить событие Removed в самом узле и инициировать событие, когда объект должен быть оставлен. Каждый раз, когда вы хотите сохранить новую ссылку на узел , вы должны подписаться на событие с соответствующим делегатом, который обнуляет ссылку на этот объект. Конечно, если вы делаете это с набором ранее известных типов, которые определенным образом ссылаются на узел, могут быть более простые и эффективные способы выполнения задачи.

6
ответ дан 7 December 2019 в 07:41
поделиться

Некоторому классу, содержащему ссылку на узел, не понравится, если какой-то механизм просто удалит эту ссылку. И нет, другого выхода нет. Вам нужно выполнить итерацию и вручную установить для них значение null. Но если Node представляет собой ограниченный или ресурсоемкий ресурс, вам следует подумать об управлении доступом к нему лучше, возможно, из центра.

0
ответ дан 7 December 2019 в 07:41
поделиться

Я рекомендую сделать так, чтобы только ваш график знал о ветвях и узлах. Таким образом, вы можете контролировать доступ и быть уверенным, что знаете, как сделать недействительными все свои собственные ссылки. Если вам нужно предоставить доступ к пользовательским данным на узле, вы можете предоставить методы для итерации по вашей структуре, вместо того, чтобы предоставлять доступ к необработанной структуре. Вы можете встраивать информацию о пользователе в классы структуры с помощью универсальных шаблонов (т. Е. Определяемого пользователем свойства Tag для каждого узла и каждой ветви).

0
ответ дан 7 December 2019 в 07:41
поделиться

Вы, безусловно, можете запросить элементы вашей ветки на предмет ссылок на каждый узел, который вы удаляете, что-то вроде этого примера

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 более многочисленны.

0
ответ дан 7 December 2019 в 07:41
поделиться

Попробуйте WeakReference в качестве оболочки для Node или Branch, списки будут содержать эти слабые ссылки.

0
ответ дан 7 December 2019 в 07:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: