ITakeValue <T> CreateTargetNode <T>(ITargetDefinition <T> target, Action <Exception> onError) { // TODO this smells: generally when you switch on a type like that it's that you should be doing a polymorphic call somewhere else. // shouldn't it be like that instead: // - an ActionDefinition know how to create a WriteOnlyNode (which could be renamed ActionNode btw) // - a MemberDefinition know how to create ReadWriteNode (which could be renamed MemberNode) // - a FormulaDefinition know how to create ReadOnlyNode (which could be renamed FormulaNode) // Jake: If we do that the internals need to be opened up and the public API will start bleeding implementation details. // I think it is better to have the switch? switch (target.NodeType) { case NodeType.Formula: throw new ArgumentException("Formula nodes cannot be a value target"); case NodeType.Member: var memberDefinition = (MemberDefinition <T>)target; var getValueDelegate = memberDefinition.CreateGetValueDelegate(); var setValueDelegate = memberDefinition.CreateSetValueDelegate(); if (!memberDefinition.IsWritable) { throw new InvalidOperationException("A readonly member cannot be a target"); } var shouldTrackChanges = !memberDefinition.SourceType.IsValueType; var visualisationInfo = new VisualisationInfo(NodeType.Member, IsRoot(memberDefinition)); return(new ReadWriteNode <T>(getValueDelegate, setValueDelegate, target.FullPath, memberDefinition.PathFromParent, visualisationInfo, nodeRepository, shouldTrackChanges, onError)); case NodeType.Action: return(new WriteOnlyNode <T>(target.CreateSetValueDelegate(), onError, target.FullPath)); default: throw new ArgumentOutOfRangeException(); } }
IValueSource <T> CreateSourceNode <T>(ISourceDefinition <T> source, Action <Exception> onError) { switch (source.NodeType) { case NodeType.Formula: var getValue = source.CreateGetValueDelegateWithCurrentValue(); return(new ReadOnlyNodeInfo <T>(getValue, source.FullPath, source.PathFromParent, nodeRepository, false, onError, new VisualisationInfo(NodeType.Formula, false))); case NodeType.Member: var memberDefinition = (MemberDefinition <T>)source; var getValueDelegate = memberDefinition.CreateGetValueDelegate(); var shouldTrackChanges = !source.SourceType.IsValueType; var visualisationInfo = new VisualisationInfo(NodeType.Member, IsRoot(memberDefinition)); if (memberDefinition.IsWritable) { return(new ReadWriteNode <T>(getValueDelegate, memberDefinition.CreateSetValueDelegate(), source.FullPath, memberDefinition.PathFromParent, visualisationInfo, nodeRepository, shouldTrackChanges, onError)); } return(new ReadOnlyNodeInfo <T>(_ => getValueDelegate(), memberDefinition.FullPath, memberDefinition.PathFromParent, nodeRepository, shouldTrackChanges, onError, visualisationInfo)); default: throw new ArgumentOutOfRangeException(); } }
public NodeMetadata(VisualisationInfo visualisationInfo, string label, string id) { this.VisualisationInfo = visualisationInfo; Label = label; Id = id; }