This works for me:
Func<MyObject, IEnumerable<MyObject>> flatten = null;
flatten = mo =>
new [] { mo }
.Concat(mo.MyChildren.SelectMany(x => flatten(x)));
var map = flatten(root).ToDictionary(x => x.ID);
Func<int, IEnumerable<MyObject>> getAncestorPath = null;
getAncestorPath = g =>
map.ContainsKey(g)
? new [] { map[g] }.Concat(getAncestorPath(map[g].ParentID))
: Enumerable.Empty<MyObject>();
To make this work I have to change the List<MyObject> MyChildren { get; set; }
property to public
. If you don't do this we need to know of some other way to get a list of MyObject
so that we don't have to traverse the tree.
So, if I start with this object tree:
var root = new MyObject()
{
ID = 1,
ParentID = 0,
MyChildren = new List<MyObject>()
{
new MyObject()
{
ID = 2,
ParentID = 1,
MyChildren = new List<MyObject>()
{
},
},
new MyObject()
{
ID = 3,
ParentID = 1,
MyChildren = new List<MyObject>()
{
new MyObject()
{
ID = 4,
ParentID = 3,
MyChildren = new List<MyObject>()
{
},
}
},
}
},
};
And I ask for getAncestorPath(4)
then I get this result:

Or, if I show it as a series of ids using String.Join(", ", getAncestorPath(someId).Select(x => x.ID))
then I get this:
4, 3, 1
If you have a list of roots, rather than a single root, then the code changes like so:
var map = roots.SelectMany(root => flatten(root)).ToDictionary(x => x.ID);