Your question is how you can perform actions for different types of code tree nodes, right?
Start by announcing a new interface called INodeActor , which gives you a contract on how your code can affect nodes in the code tree. This definition will look something like this:
public interface INodeActor { bool CanAct(CodeTree treeNode); void Invoke(CodeTree treeNode); }
Now you can take the following code:
foreach (CodeTree code in tree.Codes) { if (code.GetType() == typeof(VariablesDecleration)) { VariablesDecleration codeVariablesDecleration = (VariablesDecleration) code; // do class related stuff that has to do with VariablesDecleration } else if (code.GetType() == typeof(LoopsDecleration)) { LoopsDecleration codeLoopsDecleration = (LoopsDecleration) code; // do class related stuff that has to do with LoopsDecleration } }
And get upset:
public class VariablesDeclerationActor : INodeActor { public void CanAct(CodeTree node) { return node.GetType() == typeof(VariablesDecleration); } public void Invoke(CodeTree node) { var decl = (VariablesDecleration)node;
Composer
Think of a composer for a work coordinator. He does not need to know how the actual work is done. The responsibility is to cross the code tree and delegate the work to all registered participants.
public class Composer { List<INodeActor> _actors = new List<INodeActor>(); public void AddActor(INodeActor actor) { _actors.Add(actor); } public void Process(CodeTree tree) { foreach (CodeTree node in tree.Codes) { var actors = _actors.Where(x => x.CanAct(node)); if (!actors.Any()) throw new InvalidOperationException("Got no actor for " + node.GetType()); foreach (var actor in actors) actor.Invoke(node); } } }
Using
You can customize the execution as you like without changing the workaround or any existing code. Thus, the code now follows the principles of SOLID.
var composer = new Composer(); composer.Add(new VariablesDeclerationActor()); composer.Add(new PrintVariablesToLog()); composer.Add(new AnalyzeLoops());
If you want to build the result, you can enter the context that is passed to the INodeActor invoke method:
public interface INodeActor { bool CanAct(CodeTree treeNode); void Invoke(InvocationContext context); }
If the context contains a node for processing, perhaps StringBuilder to store the result, etc. Compare it to the HttpContext in ASP.NET.
jgauffin
source share