2010-04-27 9 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; 
} 

, 그것은 여전히 ​​가능 정말 무엇을 반면 I 제거 된 노드에 대한 참조를 null로 설정하고 가비지 콜렉션을 시작하도록하는 것이 좋습니다.

각 분기를 열거하고 각 노드 참조를 순차적으로 확인하는 것 외에 참조를 제거하는 방법에 대한 현명한 아이디어가 있습니까? 각 Branch 인스턴스의 노드 및 실제로 제거 된 Node를 참조하는 다른 클래스에?

+1

사실 분기에 데이터를 저장하고 있습니까? 그렇지 않으면 해당 클래스를 완전히 제거하고 관련 노드를 Node 클래스에 저장하면됩니다. –

+0

안녕하세요, 저는 다른 데이터를 저장하고 있습니다. 위의 데이터 구조는 실제 모델의 참조가 어디에 있는지 보여주는 간단한 예제 일뿐입니다. – LiamV

답변

1
는에있는 지점의 목록을 포함하도록 노드를 변경

. 노드를 제거하면 모든 분기가 제거됩니다. 분명히 노드와 분기를 추가하고 제거하는 모든 메서드를 캡슐화하므로 외부 코드가 구조를 손상시킬 수 없습니다.

브랜치에 데이터를 실제로 저장하지 않는 경우 (일반적으로 에지라고도 함) 전혀 필요하지 않습니다. 노드는 연결하는 다른 노드의 목록을 유지 관리 할 수 ​​있습니다.

+0

주어진 정보를 기반으로 노드 또는 분기 목록이 필요하지 않은 것은 맞습니다. 고려해야 할 다른 요소가있을 수 있습니다. 예를 들어이 데이터는 실제로 데이터베이스 내에 저장되므로 데이터베이스 테이블에 매핑되는 각 유형의 목록을 갖는 것이 더 적합합니다. – LiamV

+0

이 구조체는 데이터베이스에 쉽게 매핑 할 수 있습니다 : 노드 테이블, 에지 테이블, 그들 사이의 FK 관계. 그것은 100 % 관계형 모델입니다. EF 4는 별도의 작업없이 지연로드 에지 및 노드 주변의 모든 문제를 처리 할 수 ​​있습니다. 엔터티 데이터 모델로 데이터베이스를 가져올 때 무료로 Node.Edges를 자동으로 가져옵니다. 실제로는 삭제도 쉽게 할 수 있습니다. Edge를 제거하면 각 노드에서 자동으로 제거 할 수 있습니다. –

0

일부 메커니즘은이 참조를 삭제하는 경우 노드에 대한 참조를 보유하는 일부 클래스는이를 좋아하지 않습니다. 그리고 다른 방법은 없습니다. 수동으로 null을 반복하고 설정해야합니다. 그러나 Node가 제한적이거나 메모리 집약적 인 리소스를 나타내는 경우 액세스를 중앙에서 더 잘 관리하는 것이 좋습니다.

+0

모든 답변을 주셔서 대단히 감사합니다. 확실히 생각해 볼 일이 있습니다. Hightechrider가 제안한 경로를 따라 가면서 문제가 발생할 때까지 내려갈 것이라고 생각합니다. 그런 이유로 나는 그의 대답을 받아 들였습니다. – LiamV

6

내장 된 C# 언어 기능이 없기 때문에 (실제로 과제를 추적 할 수는 없습니다). 어딘가에 모든 참조를 추적하고 새로운 참조를 지정하는 즉시 업데이트해야합니다. 매우 일반적인 아이디어는 Node 자체에 Removed 이벤트를 제공하고 객체를 포기해야하는 경우 이벤트를 발생시키는 것입니다. Node에 대한 새 참조를 유지할 때마다 해당 객체에 대한 참조가 null 인 일치하는 대리자를 사용하여 이벤트를 구독합니다. 물론 특정 방식으로 노드를 참조하는 이전에 알려진 유형으로이 작업을 수행하는 경우 작업을보다 쉽고 효율적으로 수행 할 수 있습니다.

0

노드 또는 분기에 대한 래퍼로 WeakReference를 사용하면 목록에 약한 참조가 포함됩니다.

+1

WeakReference는 가비지 수집 문제를 제거하지만 노드가 제거 되 자마자 다른 위치에서 데이터 구조를 적절하게 업데이트해야 할 경우 문제를 해결하지 않습니다. –

+0

그래서 이벤트 OnAdded, OnRemoved 및 backward reference를 유지합니다. 각 노드는 자신이 속한 지점에 대해 알게됩니다. –

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 객체에 대한 참조가 더 많으면 모든 참조를 제거하는 것이 점점 더 어려워집니다. 가 필요한 모두는 하나의 루트 노드입니다

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 
} 

지금 당신의 그래프 클래스는 노드 또는 지점의 목록을 필요로하지 않습니다

0

그래프에만 분기 및 노드를 알리도록 설정하는 것이 좋습니다. 그렇게하면 액세스를 제어 할 수 있고 자신의 모든 참조를 무효화하는 방법을 알 수 있습니다. 노드에서 사용자 데이터에 대한 액세스를 제공해야하는 경우 원시 구조에 액세스하지 않고 구조를 반복하는 메서드를 제공 할 수 있습니다. 제네릭을 통해 구조 클래스에 사용자 정보를 임베드 할 수 있습니다 (즉, 각 노드 및 각 분기에 대한 사용자 정의 '태그'속성).