First, suppose you have a single node. You wish to get the path to the root.
Let's represent a path to a root as a sequence of nodes.
We can build this write a method that takes an item and a function that identifies the next item, and returns the sequence.
public static IEnumerable<T> Path(T item, Func<T, T> nextItem) where T : class
{
T current = item;
while(current != null)
{
yield return current;
current = nextItem(current);
}
}
Now you can write queries on your list of objects.
List<Node> nodes = whatever;
var paths = from node in nodes
select Path(node, n=>GetNodeById(n.Parent));
And now you have a sequence of sequences of nodes.
Suppose instead you want a sequence of sequences of strings:
var namePaths =
from node in nodes
select (from pathElement in Path(node, n=>GetNodeById(n.Parent))
select pathElement.Name);
And so on.
Make sense?