Some stupid task about Expression trees.
Write down a simplest expression tree visitor (inherited from System.Linq.Expressions.ExpressionVisitor) that will have a static method:
Write down a simplest expression tree visitor (inherited from System.Linq.Expressions.ExpressionVisitor) that will have a static method:
public static IEnumerable<Expression>
All(Expression
node)
This method should return lazy enumeration of all expression in a an expression tree represented by node. By "lazy" I mean that a tree should not be entirely flattered into a list like this:
This visitor will traverse entire expression tree - the Visit() method will be called on every node regardless of how much nodes I really want to visit. The task is to minimize the footprint and visit as less nodes as possible.
The lazy visitor should return expressions in the same order as NonLazyVisitor above.
The following solution is not fully lazy - it enumerates all child nodes (but not all descendants) when visits a particular node:
The main idea is to collect all children to a list and then enumerates all grand-children of children in lazy manner - SelectMany() enumerator will be called only when a child is actually enumerated.
class NonLazyVisitor : ExpressionVisitor
{
readonly
List<Expression>
_nodes = new List<Expression>();
public
static IEnumerable<Expression> All(Expression node)
{
var visitor = new NonLazyVisitor();
visitor.Visit(node);
return visitor._nodes;
}
public
override Expression
Visit(Expression
node)
{
_nodes.Add(node);
return base.Visit(node);
}
}This visitor will traverse entire expression tree - the Visit() method will be called on every node regardless of how much nodes I really want to visit. The task is to minimize the footprint and visit as less nodes as possible.
The lazy visitor should return expressions in the same order as NonLazyVisitor above.
The following solution is not fully lazy - it enumerates all child nodes (but not all descendants) when visits a particular node:
internal sealed class LazyVisitor
: ExpressionVisitor
{
private readonly List<Expression>
_children = new
List<Expression>();
public override Expression Visit(Expression node)
{
_children.Add(node);
return node;
}
public static IEnumerable<Expression>
All(Expression
node)
{
var visitor = new LazyVisitor();
return visitor.AllInternal(node);
}
internal IEnumerable<Expression> AllInternal(Expression node)
{
yield return node;
base.Visit(node);
var nestedVisitor = new
LazyVisitor();
foreach (var descendant
in from child in _children
from descendants in nestedVisitor.AllInternal(child)
select descendants)
{
yield return descendant;
}
}
}
Извиняюсь за корявый код:
ReplyDeleteclass LazyVisitor : ExpressionVisitor
{
bool firstVisit;
int insertIndex ;
readonly List _nodes = new List();
public static IEnumerable All(Expression node)
{
var visitor = new LazyVisitor();
int currentIndex = -1;
visitor._nodes.Add(node);
while(visitor._nodes.Count > currentIndex + 1)
{
currentIndex++;
visitor.PerformVisit(currentIndex);
yield return visitor._nodes[currentIndex];
}
}
public void PerformVisit(int currentIndex)
{
firstVisit = true;
insertIndex = currentIndex + 1;
Visit(_nodes[currentIndex]);
}
public override Expression Visit(Expression node)
{
if(firstVisit)
{
firstVisit = false;
return base.Visit(node);
}
else{
_nodes.Insert(insertIndex, node);
insertIndex++;
return node;
}
}
}
Да, это работает
Delete