简体   繁体   中英

How is the interaction between LinkedList<T> and LinkedListNode<T> implemented in C#?

First, let's define a node:

LinkedListNode<int> node = new LinkedListNode<int>(43);

You'll notice that the properties node.List , node.Next and node.Previous are all get only. Now let's add the node to a LinkedList :

LinkedList<int> linkedlist = new LinkedList<int>();
linkedlist.AddFirst(node);

At this point, the property node.List will have change to contain a reference to linkedlist . Similarly, if other nodes are added to the LinkedList , the Next and Previous properties will be updated to reflect the structure of the linked list, even though these properties do not expose a public set accessor.

How is this behavior implemented?

I know how to do it using internal , but is there a better way? For example, suppose I have a single assembly that contains many types, not just LinkedList and LinkedListNode . By making the setters for the node properties List , Previous and Next , I am exposing these setters to the whole assembly, which is undesired.

How is this behavior implemented?

Without looking at the source, I would guess the setters or backing fields for those properties are marked internal and therefore accessible from LinkedList<T> since they both sit in the same assembly.

but is there a better way?

Not really. Let me elaborate. There are other options.

  1. You could make LinkedListNode<T> an inner class defined in LinkedList<T> . That's an option, but it's burdensome on callers.

  2. You could carve LinkedList<T> and LinkedListNode<T> into their own assembly. That's obviously a burden on users and could quickly degrade into a maintenance debacle.

I characterize both of these as not being better solutions.

I checked with ILSpy, the read-only properties are backed by internal fields.

internal LinkedListNode<T> next;

public LinkedListNode<T> Next {
    get {
        if (this.next != null && this.next != this.list.head) {
            return this.next;
        }
        return null;
    }
}

As for how to do it differently, and a discussion of whether you'd want to, see this question and its answers.

Jason is correct. I had a look at the source and LinkedListNode<T> has internal backing fields.

One way to do this is with nested classes. I don't know if this qualifies as a "better" way, but it does avoid internal setters/fields. I've left out some of the implementation, so you can see an outline of the structure:

public class Node<T>
{
  private List list;
  private Node<T> prev, next;

  public List List { get { return list; } }
  // other accessors.

  public abstract class List
  {
    Node<T> head;

    internal List() { }

    public AddFirst(Node<T> node)
    {
        // node adding logic.
        node.list = this;       
    }

    // implementation elided for brevity
  }

}

public class MyLinkedList<T> : Node<T>.List { }

Now you can declare a MyLinkedList and add nodes to it, but there are no internal accessors on Node<T> .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM