lengthy software architecture question ahead
CLARITY EDIT: I am trying to convert an object graph that consists of types like
NodeA, NodeB, ... to an object graph that consists of types like *My*NodeA, *My*NodeB ..., and vice versa. The properties in the NodeX types correspond to similar properties in the MyNodeX types, but in many cases it is not just a trivial assignment.
If I have two similar class structures like this:
// pure model, i.e. minimal information that is convenient for storage
abstract class Node
{
public int BaseProperty { get; set; }
public NodeCollection Children { get; private set; } // : Collection<Node>
}
class NodeA /* NodeB, NodeC ... */ : Node
{
public int DerivedAProperty { get; set; }
}
and
// objects that are convenient for being used by the application
abstract class MyNode
{
public int MyBaseProperty { get; set; }
public MyNodeCollection Children { get; private set; } // : Collection<MyNode>
}
class MyNodeA /* MyNodeB, MyNodeC ... */ : MyNode
{
public int MyDerivedAProperty { get; set; }
}
, and I need to convert an object graph of the NodeX type to one of the MyNodeX type, or vice versa, without changing any of the NodeX classes at all, I've found myself using this pattern regularly:
NodeX -> MyNodeX
// USAGE / external code
Node node = ...
MyNode myNode = MyNode.Load(node, ARGS); // static factory
abstract class MyNode
{
...
// factory
public static MyNode Load(Node node, ARGS)
{
var type = node.GetType();
MyNode myNode;
// no 'is' usage because NodeB could be derived from NodeC etc.
if (type == typeof(NodeA))
myNode = new MyNodeA(ARGS); // arbitrary ctor
else if (...)
...
myNode.Load(Node);
return myNode
}
public virtual void Load(Node node)
{
this.MyBaseProperty = node.BaseProperty;
foreach (var child in node.Children)
this.Children.Add(MyNode.Load(child, this.ARGS));
}
}
class MyNodeA : MyNode
{
...
public override void Load(Node node)
{
var m = (NodeA)node; // provoke InvalidCastException if coding error
base.Load(node);
this.MyDerivedAProperty = m.DerivedAProperty;
}
}
MyNodeX -> NodeX
// USAGE / external code
MyNode myNode = ...
Node node = myNode.Commit();
abstract class MyNode
{
...
// 'kind of' factory
public abstract Node Commit();
public virtual Commit(Node node)
{
node.BaseProperty = this.MyBaseProperty;
foreach (var child in this.Children)
node.Children.Add(child.Commit());
}
}
class MyNodeA : MyNode
{
...
public override Node Commit()
{
var m = new NodeA(); // "factory" method for each type
this.Commit(m);
return m;
}
public override void Commit(Node node)
{
var m = (NodeA)node; // provoke InvalidCastException if coding error
base.Commit(node);
m.DerivedAProperty = this.MyDerivedAProperty;
}
}
I have used this approach multiple times successfully and I generally like it, because the methods that have to be added to the class are straight forward, and so is the external code. Also, it avoids code duplication by calling base.Load(node) / base.Commit(node). However, I really don't like that if/else ladder in the static Load factory method.
I would prefer to have a factory method in each type for the Node -> MyNode (Load) case, similar to how it is in the MyNode -> Node (Commit) case. But static and virtual is obviously a bit problematic. I would also prefer to not do the two casts I have to do now.
Is achieving such a thing somehow possible?
My recommendation would be to solve the problem incrementally. First you'll need something to traverse the tree and convert each node along the way:
public static class NodeExtensions
{
public static MyNode ToMy( this Node node )
{
var result = node.Transform();
result.Children = node.Children.Select( ToMy ).ToList();
}
public static Node FromMy( this MyNode node )
{
var result = node.Transform();
result.Children = node.Children.Select( ToMy ).ToList();
}
public static MyNode Transform( this Node node )
{
// TODO code to transform any single node here
}
public static Node Transform( this MyNode node )
{
// TODO code to transform any single node here
}
}
Since you mention that the transformation from Node to MyNode is not a simple matter of copying properties, yet also indicate that there will be a lot of that going on, my initial thought is that this is a task for AutoMapper.
AutoMapper lets you create a "conversion profile" that describes which properties to map and any special rules you want to apply to any given mapping. Also, it provides both generic and non-generic methods, so you can use it even if you do not know the types at compile-time. It is commonly used to convert between entities and view models, so you'll find plenty of questions and answers related to its usage elsewhere here.
Defining type maps basically consists of a number of calls like this:
Mapper.CreateMap<Node,MyNode>(); // no special rules for this map
You'll have to consule the AutoMapper documentation for the specifics about how to create special mappings, like splitting properties or performing type conversions. You'll also need to create maps going both ways in order to be able to map in either direction.
Once you have defined all of your mappings, the Transform extension methods can be as simple as:
public static MyNode Transform( this Node node )
{
return Mapper.Map( node.GetType(), node.GetMatchingMyType(), node );
}
public static Type GetMatchingType( this Node node )
{
// you can use a dictionary lookup or some other logic if this doesn't work
var typeName = "My" + node.GetType().Name;
return typeof(MyNode).Assembly.GetTypes().Single( t => t.Name == typeName );
}
When everything is in place, you can convert the entire tree by writing:
var myTree = node.ToMy();
// and back
node = myTree.FromMy();
Is everything as consistently named as you present above?
If so, you could build a set of generic convert-to convert-from functions that use reflection.
Here is what I'm thinking (this is stream of conciousness, not verified compiled code):
<T> ConvertTo<TMy, T>(TMy object)
{
// create an object of type T
T newObj = new T();
// iterate the members of T using reflection
foreach(member in T)
{
// find the equavalent My members in TMy
// transfer the data
}
return newObj;
}
I will look into this a bit more and possibly generate working code sometime this weekend.
Related
I found a question here that almost answers my question, but I still don't fully understand.
Trying to write a Tree data structure, I did this:
public class Tree<T>
{
public TreeNode<T> root;
...
public class TreeNode<T>
{
List<TreeNode<T>> children;
T data;
public T Data { get { return data; } }
public TreeNode<T>(T data)
{
this.data = data;
children = new List<TreeNode<T>>();
}
...
}
}
And, anyone who's worked with C# generics apparently knows that I got this compiler warning: Type parameter 'T' has the same name as the type parameter from outer type 'Tree<T>'
My intent was to create an inner class that would be forced to use the same type as the outer class, but I now understand that adding a type parameter actually allows the inner class to be more flexible. But, in my case, I want subclasses of Tree<T> to be able to use TreeNode, for example, like this:
public class IntTree : Tree<int>
{
...
private static IntTree fromNode(TreeNode<int> node)
{
IntTree t = new IntTree();
t.root = node;
return t;
}
}
(That method allows the subclass to implement ToString() recursively)
So my question is, if I take out the parameterization, like this:
public class Tree<T>
{
public TreeNode root;
...
public class TreeNode
{
List<TreeNode> children;
T data;
public T Data { get { return data; } }
public TreeNode(T data)
{
this.data = data;
children = new List<TreeNode>();
}
...
}
}
will the resulting subclass be forced to use integers when creating TreeNodes, and therefore never be able to break the intent I had?
Disclaimer: yes, I know I'm probably doing plenty of things wrong here. I'm still learning C#, coming from a mostly Java and Lisp background, with a little bit of plain C. So suggestions and explanations are welcome.
Yes, it will be forced to use the same type. Look at the declaration again:
public class Tree<T>
{
public class TreeNode
{
private T Data;
}
}
So the type of Data is determined when you instantiate a specific Tree:
var tree = new Tree<int>();
This way the type of Data is declared as int and can be no different.
Note that there is no non-generic TreeNode class. There is only a Tree<int>.TreeNode type:
Tree<int> intTree = new Tree<int>(); // add some nodes
Tree<int>.TreeNode intNode = intTree.Nodes[0]; // for example
Tree<string> stringTree = new Tree<int>(); // add some nodes
Tree<string>.TreeNode stringNode = stringTree.Nodes[0]; // for example
// ERROR: this won't compile as the types are incompatible
Tree<string>.TreeNode stringNode2 = intTree.Nodes[0];
A Tree<string>.TreeNode is a different type than Tree<int>.TreeNode.
The type T declared in the outer class may already be used in all its inner declarations, so you can simply remove the <T> from the inner class:
public class Tree<T>
{
public TreeNode root;
//...
public class TreeNode
{
List<TreeNode> children;
T data;
public T Data { get { return data; } }
public TreeNode(T data)
{
this.data = data;
children = new List<TreeNode>();
}
//...
}
}
I am writing the function which will return particular node from tree structure. But when I search in a tree using LINQ it is searching in the first branch and finally when it reaches to leaf it is throwing null reference exception as leaf don't have any child.
Here is my class,
public class Node
{
public int Id { get; set; }
public string Name { get; set; }
public string Content { get; set; }
public IEnumerable<Node> Children { get; set; }
public IEnumerable<Node> GetNodeAndDescendants() // Note that this method is lazy
{
return new[] { this }
.Concat(Children.SelectMany(child => child.GetNodeAndDescendants()));
}
}
This is how I am calling this function,
var foundNode = Location.GetNodeAndDescendants().FirstOrDefault(node => node.Name.Contains("string to search"));
OR
var foundNode = Location.GetNodeAndDescendants().FirstOrDefault(node => node.Id==123)
What would be the correct way to do this? and any sample code would be grateful
Nothing wrong to write your own function, but implementation based on LINQ or recursive iterator is not a good idea (performance!). But why depending on external libraries? A lot of code that you don't need, implementing interfaces, modifying your classes etc. It's not hard to write a generic function for pre-order tree traversal and use it for any tree structure. Here is a modified version of my participation in How to flatten tree via LINQ? (nothing special, ordinary iterative implementation):
public static class TreeHelper
{
public static IEnumerable<T> PreOrderTraversal<T>(T node, Func<T, IEnumerable<T>> childrenSelector)
{
var stack = new Stack<IEnumerator<T>>();
var e = Enumerable.Repeat(node, 1).GetEnumerator();
try
{
while (true)
{
while (e.MoveNext())
{
var item = e.Current;
yield return item;
var children = childrenSelector(item);
if (children == null) continue;
stack.Push(e);
e = children.GetEnumerator();
}
if (stack.Count == 0) break;
e.Dispose();
e = stack.Pop();
}
}
finally
{
e.Dispose();
while (stack.Count != 0) stack.Pop().Dispose();
}
}
}
and your function inside the class Node becomes:
public IEnumerable<Node> GetNodeAndDescendants() // Note that this method is lazy
{
return TreeHelper.PreOrderTraversal(this, node => node.Children);
}
Everything else stays the way you did it and should work w/o any problem.
EDIT: Looks like you need something like this:
public interface IContainer
{
// ...
}
public class CustomerNodeInstance : IContainer
{
// ...
}
public class ProductNodeInstance : IContainer
{
// ...
}
public class Node : IContainer
{
// ...
public IEnumerable<IContainer> Children { get; set; }
public IEnumerable<IContainer> GetNodeAndDescendants() // Note that this method is lazy
{
return TreeHelper.PreOrderTraversal<IContainer>(this, item => { var node = item as Node; return node != null ? node.Children : null; });
}
}
If you don't mind taking a dependency on a third party solution I have a lightweight library that I have been working on that can do this and many other things with just about any tree. It is called Treenumerable. You can find it on GitHub here: https://github.com/jasonmcboyd/Treenumerable; and the latest version (1.2.0 at this time) on NuGet here: http://www.nuget.org/packages/Treenumerable. It has good test coverage and seems to be stable.
It does require that you create a helper class that implements an ITreeWalker interface with two methods: TryGetParent and GetChildren. As you might guess TryGetParent gets a node's parent so your Node class would have to be modified in a way that it is aware of its parent. I guess you could just throw a NotSupported exception in TryGetParent as that method is not necessary for any of the traversal operations. Anyway, regardless of which way you go the following code would do what you want:
ITreeWaler<Node> walker;
// Don't forget to instantiate 'walker'.
var foundNode =
walker
.PreOrderTraversal(Location)
.FirstOrdefault(node => node.Name.Contains("string to search"));
One difference worth mentioning between my implementation and yours is that my implementation does not rely on recursion. This means you don't have to worry about a deep tree throwing a StackOverflowException.
I have a class that may have a parent, or list of children of the same type of it's own. The following code snippet should explain my scenario.
public abstract class X{
public virtual List<X> ChildItems { get; set; }
public virtual X ParentItem { get; set; }
}
I would like to know if there is a particularly efficient method to traverse the objects from an object of type X, checking if the object has a parent, or children starting from bottom up.
public static void SaveSetup(X obj) {
//logic here
}
Any help is appreciated.
What you are dealing with is a tree structure (or possibly many disconnected tree structures). A tree structure has a root element. Usually, a tree structure is traversed starting from the root. If you want to start from any element in the tree, I suggest you to first get the root element and then traverse in the usual manner.
The easiest way to traverse a recursive structure is to use recursive method, i.e., a method that calls itself.
public abstract class X
{
public virtual List<X> ChildItems { get; set; }
public virtual X ParentItem { get; set; }
// Method for traversing from top to bottom
public void Traverse(Action<X> action)
{
action(this);
foreach (X item in ChildItems) {
item.Traverse(action);
}
}
// Get the root (the top) of the tree starting at any item.
public X GetRootItem()
{
X root = this;
while (root.ParentItem != null) {
root = root.ParentItem;
}
return root;
}
}
Now you can save the setup with
X root = item.GetRootItem();
root.Traverse(SaveSetup);
Example with lambda expression. Prints every item of the tree assuming that ToString() has been overridden to return a meaningful string.
root.Traverse(x => Console.WriteLine(x));
Traverse from given object to root (ParentItem = null)
public static void SaveSetup(X obj) {
while (obj != null)
{
// logic here
obj = obj.ParentItem;
}
}
I'm building up a tree to parse some text, so I've created some nodes:
abstract class Node { }
class TextNode : Node
{
public readonly string Text;
public TextNode(string text)
{
Text = text;
}
public TextNode(char ch)
{
Text = ch.ToString();
}
}
class VariableNode : Node
{
public readonly string Name;
public VariableNode(string name)
{
Name = name;
}
}
I'm going to add some "branching" nodes pretty soon (nodes that contain other nodes).
I'm wondering about the best way to process them. Right now I've got some code that looks like this:
foreach (var item in nodes)
{
if (item is TextNode)
sb.Append(((TextNode)item).Text);
if (item is VariableNode)
sb.Append(dict[((VariableNode)item).Name]);
}
Which seems a bit clunky, and will only get worse as I add to it.
Should I
Try to encapsulate the logic into the base Node class somehow so that I can just the DoStuff() function without worrying about type-casting?
Should I add some kind of enum for each node type so that I can use a switch instead of a foreach loop?
Something else?
Need to give you guys a bit more context. In the example above, variables nodes need access to the dict to render themselves.
I'm parsing a template. In the template, there are variables. The variable names and their values are stored in the dict. At parse time, I don't have the values (well, I could, but I want to be able to re-render the template with different values), so I need to be able to pass in different dicts to the template. The way I have it set up, the template does all the rendering, the nodes do nothing. I guess I could pass the dict one more level down to each node so they can render themselves...
To elaborate on #1
// in class Template
public string Render(Dictionary<string, object> dict)
{
var sb = new StringBuilder();
foreach (var item in nodes)
sb.Append(item.Render(dict));
return sb.ToString();
}
interface INode {
string Render(Dictionary<string, object> dict);
}
class TextNode : INode
{
private string _text;
public TextNode(string text)
{
_text = text;
}
public TextNode(char ch)
{
_text = ch.ToString();
}
public string Render(Dictionary<string, object> dict)
{
return _text;
}
}
class VariableNode : INode
{
private string _name;
// TODO: filters...
public VariableNode(string name)
{
_name = name;
}
public string Render(Dictionary<string, object> dict)
{
return dict[_name].ToString();
}
}
I guess that isn't such a bad solution either.
Solutions so far:
Use an enum and switch
Build a dictionary of type/actions to make the switch a bit cleaner
Polymorphism (x2)
Visitor pattern (haven't read this yet)
Use ANTLR -- although ANTLR will build a tree and then this problem applies again
You can instead use an interface and define a enum property, for eg. NodeType Type where Type is an enum with values TextNode, VariableNode. Although, here also you will need to cast the node to get the value. You can try to add a property named Value which returns Text or Name depending on the NodeType. If dict is accessible from VariableNode, Value can return the exact value needed for your method.
All in all, I think interfaces suit your requirements better than an abstract class.
If you're going to have lots of different node types with different behaviours I would certainly consider using a base class Node and then implementing a specialized node class for each type that implements the specific behaviour.
An alternative to putting tree processing logic into the nodes is to use the visitor pattern. In this case you would tend to have a more homogeneous tree structure with the specific processing rules maintained outside the tree.
If this tree is for the purpose of parsing text have you looked at Antlr? This tool can generate your syntax tree for you, based on a specified grammar.
Move your foreach(var item in nodes) into a method (i.e. BuildAll) in the abstract node class, create an abstract / virtual method Build (in the abstract Node class) and call the method Build() in the BuildAll and let it output a string...
Like so:
public abstract string Build();
public string BuildAll() {
var output = new StringBuilder();
foreach(var node in nodes) {
output.append(node.Build());
}
return output.toString();
}
and override it inside each actual implementation of node...
so TextNode will have...
public override string Build() {
return ... extract whatever you want from TextNode;
}
In this case, your base class does not need to know the exact implementation of its descendant, thus does not break the Open Close Principle.
You can create a Dictionary<Type,Action<T>> - the keys are the node types and the Action<T> delegates are what you do with each.
You can than simply do:
Dictionary[typeof(variable)];
In order to execute the right action for each type.
Polymorphism is exactly what you want. Something like this:
class Node
{
public virtual string ToDisplayText(params object[] parameters)
{
return string.Empty;
}
}
class TextNode : Node
{
public override string ToDisplayText(params object[] parameters)
{
return this.Text;
}
}
class VariableNode : Node
{
public override string ToDisplayText(params object[] parameters)
{
//check parameters
var dict = (Dictionary<string,string>)parameters[0];
return dict[this.Name];
}
}
So you can:
foreach(var node in nodes)
{
sb.Append(node.ToDisplayText(dict));
}
Lets say I have a Node class as follows:
class Node<T>
{
T data;
List<Node<T>> children;
internal Node(T data)
{
this.data = data;
}
List<Node<T>> Children
{
get
{
if (children == null)
children = new List<Node<T>>(1);
return children;
}
}
internal IEnumerable<Node<T>> GetChildren()
{
return children;
}
internal bool HasChildren
{
get
{
return children != null;
}
}
internal T Data
{
get
{
return data;
}
}
internal void AddChild(Node<T> child)
{
this.Children.Add(child);
}
internal void AddChild(T child)
{
this.Children.Add(new Node<T>(child));
}
}
The problem is that each and every node of the tree is confined to a single type. However, there are situations where the root node is of one type, which has children of another type which has children of a third type (example documents-->paragraphs-->lines-->words).
How do you define a generic tree for such cases?
If you want a strict hierarchy of types you could declare them like this:
class Node<T, TChild> {...}
Node<Document, Node<Paragraph, Node<Line, Word>>>
I did not claim it would be pretty. :)
How do you define a generic tree for such cases?
I wouldn't try to in the first place. If what I wanted to model was:
I have a list of documents
A document has a list of paragraphs
A paragraph has a list of words
then why do you need generic nodes at all? Make a class Paragraph that has a List<Word>, make a class Document that has a List<Paragraph>, and then make a List<Document> and you're done. Why do you need to artificially impose a generic tree structure? What benefit does that buy you?
Have all of your sub-objects implement a specific eg IDocumentPart then declare Node
I have been reluctant to offer the code example attached, feeling that I don't have a strong sense, yet, of the "norms" of StackOverFlow in terms of posting code that may be "speculative," and, feeling that this particular frolic is some form of "mutant species" escaped from the laboratory on "The Island of Dr. Moreau" :) And, I do think the answer by Eric Lippert above is right-on.
So please take what follows with "a grain of salt" as just an experiment in "probing" .NET inheritance (uses FrameWork 3.5 facilities). My goal in writing this (a few months ago) was to experiment with an Abstract Class foundation for Node structure that implemented an internal List<> of "itself," then implement strongly-typed classes that inherited from the Abstract class ... and, on that foundation, build a generalized Tree data structure.
In fact I was surprised when I tested this, that it worked ! :)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// experimental code : tested to a limited extent
// use only for educational purposes
namespace complexTree
{
// foundation abstract class template
public abstract class idioNode
{
// a collection of "itself" !
public List<idioNode> Nodes { private set; get; }
public idioNode Parent { get; set; }
public idioNode()
{
Nodes = new List<idioNode>();
}
public void Add(idioNode theNode)
{
Nodes.Add(theNode);
theNode.Parent = this;
}
}
// strongly typed Node of type String
public class idioString : idioNode
{
public string Value { get; set; }
public idioString(string strValue)
{
Value = strValue;
}
}
// strongly typed Node of type Int
public class idioInt : idioNode
{
public int Value { get; set; }
public idioInt(int intValue)
{
Value = intValue;
}
}
// strongly type Node of a complex type
// note : this is just a "made-up" test case
// designed to "stress" this experiment
// it certainly doesn't model any "real world"
// use case
public class idioComplex : idioNode
{
public Dictionary<idioString, idioInt> Value { get; set; }
public idioComplex(idioInt theInt, idioString theString)
{
Value = new Dictionary<idioString, idioInt>();
Value.Add(theString, theInt);
}
public void Add(idioInt theInt, idioString theString)
{
Value.Add(theString, theInt);
theInt.Parent = this;
theString.Parent = this;
}
}
// special case the Tree's root nodes
// no particular reason for doing this
public class idioTreeRootNodes : List<idioNode>
{
public new void Add(idioNode theNode)
{
base.Add(theNode);
theNode.Parent = null;
}
}
// the Tree object
public class idioTree
{
public idioTreeRootNodes Nodes { get; set; }
public idioTree()
{
Nodes = new idioTreeRootNodes();
}
}
}
So, to the test : (call this code from some EventHandler on a WinForm) :
// make a new idioTree
idioTree testIdioTree = new idioTree();
// make a new idioNode of type String
idioString testIdioString = new idioString("a string");
// add the Node to the Tree
testIdioTree.Nodes.Add(testIdioString);
// make a new idioNode of type Int
idioInt testIdioInt = new idioInt(99);
// add to Tree
testIdioTree.Nodes.Add(testIdioInt);
// make another idioNode of type String
idioString testIdioString2 = new idioString("another string");
// add the new Node to the child Node collection of the Int type Node
testIdioInt.Nodes.Add(testIdioString2);
// validate inheritance can be verified at run-time
if (testIdioInt.Nodes[0] is idioString) MessageBox.Show("it's a string, idiot");
if (!(testIdioInt.Nodes[0] is idioInt)) MessageBox.Show("it's not an int, idiot");
// make a new "complex" idioNode
// creating a Key<>Value pair of the required types of idioNodes
idioComplex complexIdio = new idioComplex(new idioInt(88), new idioString("weirder"));
// add a child Node to the complex idioNode
complexIdio.Add(new idioInt(77), new idioString("too weird"));
// make another idioNode of type Int
idioInt idioInt2 = new idioInt(33);
// add the complex idioNode to the child Node collection of the new Int type idioNode
idioInt2.Nodes.Add(complexIdio);
// add the new Int type Node to the Tree
testIdioTree.Nodes.Add(idioInt2);
// validate you can verify the type of idioComplex at run-time
MessageBox.Show(" tree/2/0 is complex = " + (testIdioTree.Nodes[2].Nodes[0] is idioComplex).ToString());
If the "smell" of this code is as bad as the fruit that here in Thailand we call the "durian" : well, so be it :) An obvious possible "weirdness" in this experiment is that you could have references to the same Node in more than one place in the tree at the same time.