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));
}
Related
I want to rename a class, its base class and the interface that it supports. For example I want to rewrite this:-
public class CustomerDAL : DALBase, ICustomerDAL
to this:-
public class CustomerRepository : RepositoryBase, ICustomerRepository
So I wrote this CSharpSyntaxRewriter:-
public class RenameBaseClassAndInterface : CSharpSyntaxRewriter
{
public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
{
if (node.Identifier.Text.Contains("DAL"))
{
string className = node.Identifier.Text.Replace("DAL", "Repository");
node = node.ReplaceToken(node.Identifier, SyntaxFactory.Identifier(className));
if (node.BaseList != null && node.BaseList.Types != null)
{
foreach (BaseTypeSyntax baseTypeSyntax in node.BaseList.Types)
{
TypeSyntax typeSyntax = baseTypeSyntax.Type;
IdentifierNameSyntax identifierNameSyntax = (IdentifierNameSyntax)typeSyntax;
if (identifierNameSyntax.Identifier.ToString() == "DALBase")
{
node = node.ReplaceToken(identifierNameSyntax.Identifier, SyntaxFactory.Identifier("RepositoryBase"));
}
else if (identifierNameSyntax.Identifier.ToString().Contains("DAL"))
{
string repositoryInterfaceName = identifierNameSyntax.Identifier.ToString().Replace("DAL", "Repository");
node = node.ReplaceToken(identifierNameSyntax.Identifier, SyntaxFactory.Identifier(repositoryInterfaceName));
}
}
}
}
return base.VisitClassDeclaration(node);
}
}
What I actually get is this:-
public class CustomerRepository : RepositoryBase, ICustomerDAL
(i.e. ICustomerDAL does not get renamed to ICustomerRepository).
I can step through my code and I see that it reaches and executes the code to rename the interface and no error occurs, it just doesn't work. I suspect that this is because it is doing the rename on an old node and not the new node but I can't see what I have done wrong.
Any ideas?
You have your foreach loop that is trying to update all of the tokens in the base list. Once you do the first call to ReplaceToken, you've created a new node that has new identity of tokens, so the second time you call you're ReplaceToken, you're passing in a token from the original node to the call that's happening on the new node. So the second call is probably returning the existing node rather than doing a replacement. (Unfortunately ReplaceToken is a no-op if it can't find the token, which is often confusing.)
Instead of your foreach loop as written, add the tokens that need replacing (or at least analysis) into a list, and then call ReplaceTokens. This takes a list of tokens to (potentially) replace, and a lambda that we'll call for each token to rewrite it.
public override SyntaxNode VisitBaseList(BaseListSyntax node)
{
if (node.Parent is ClassDeclarationSyntax cds && cds.Identifier.Text.Contains("DAL"))
{
BaseTypeSyntax baseType = SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName("RepositoryBase"));
//...
var repositoryTypeName = SyntaxFactory.ParseTypeName(repositoryInterfaceName);
BaseTypeSyntax repositoryInterface = SyntaxFactory.SimpleBaseType(repositoryTypeName);
return SyntaxFactory.BaseList().AddTypes(baseType, repositoryInterface).NormalizeWhitespace();
}
return base.VisitBaseList(node);
}
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.
I am writing an application that allows a user to run a test. A test consists of a number of different objects, such as configuration, temperature, and benchmark. Settings and the like are saved back and forth between xml. I pass different XElements around in my code so I can build the final xml document differently for different situations. I wish to do something like this:
public abstract class BaseClass<T>
{
abstract static XElement Save(List<T>);
abstract static List<T> Load(XElement structure);
}
public class Configuration : BaseClass<Configuration>
{
public string Property1 { get; set; }
public string Property2 { get; set; }
//etc...
public static XElement Save(List<Configuration>)
{
XElement xRoot = new XElement("Root");
//etc...
return xRoot;
}
public static List<Configuration> Load(XElement structure)
{
List<BaseClass> list = new List<BaseClass>();
//etc...
return list;
}
}
public class Temperature : BaseClass<Temperature>
{
public float Value { get; set; }
public static XElement Save(List<Temperature>)
{
//save
}
public static List<Temperature> Load(XElement structure)
{
//load
}
}
[EDIT]: Revising question (Changed signatures of above functions)[/EDIT]
Of course, I am not actually allowed to override the static methods of BaseClass. What is the best way to approach this? I would like as much of the following to be valid as possible:
List<Temperature> mTemps = Temperature.Load(element);
List<Configuration> mConfigs = Configuration.Load(element);
Temperature.Save(mTemps);
Configuration.Save(mConfigs);
[EDIT]Changed intended usage code above[/EDIT]
The only solution I can think of is the following, which is NOT acceptable:
public class File
{
public static XElement Save(List<Temperature> temps)
{
//save temp.Value
}
public static XElement Save(List<Configuration> configs)
{
//save config.Property1
//save config.Property2
}
//etc...
}
Static methods aren't part of a class instance. So overriding them doesn't make any sense anyway. They can't access any nonstatic part of an instance that they happen to be a member of.
This is kind of a strategy pattern scenario, e.g. you could just have single static Load & Save methods that check the type of object passed to them, and act accordingly. But here's another slightly more clever way that uses generic types to create a prototype and call its method, allowing you to keep the logic within each derived object type.
(edit again)
Here's another crack at it, along the same lines as my original suggestion. I actually tested this and it works, so I think this is the best you can do to get all the functionality you are looking for (other than testing types and calling code conditionally). You still need to pass a type for Load, otherwise, the runtime would have no idea what kind of return is expected. But Save works universally. And the subclass implementations are strongly typed.
This just uses the first object in the list as its prototype, simple enough.
public interface IBaseObject
{
XmlElement Save(IEnumerable<IBaseObject> list);
IEnumerable<IBaseObject> Load(XmlElement element);
}
public interface IBaseObject<T> where T: IBaseObject
{
XmlElement Save(IEnumerable<T> list);
IEnumerable<T> Load(XmlElement element);
}
public class Temperature : IBaseObject<Temperature>, IBaseObject
{
public XmlElement Save(IEnumerable<Temperature> list)
{
throw new NotImplementedException("Save in Temperature was called");
}
public IEnumerable<Temperature> Load(XmlElement element)
{
throw new NotImplementedException("Load in Temperature was called");
}
// must implement the nongeneric interface explicitly as well
XmlElement IBaseObject.Save(IEnumerable<IBaseObject> list)
{
return Save((IEnumerable<Temperature>)list);
}
IEnumerable<IBaseObject> IBaseObject.Load(XmlElement element)
{
return Load(element);
}
}
// or whatever class you want your static methods living in
public class BaseObjectFile
{
public static XmlElement Save(IEnumerable<IBaseObject> list)
{
IBaseObject obj = list.DefaultIfEmpty(null).First(); // linq
return obj==null ? null : obj.Save(list);
}
public static IEnumerable<IBaseObject> Load<T>(XmlElement element)
where T: IBaseObject, new()
{
IBaseObject proto = new T();
return proto.Load(element);
}
}
(original edit)
This has a problem in that you must call the static methods with a type, e.g.
BaseClass<Temperature>.Load()
There is a way around this for the Save method, but part of what you want is not possible. The Load method cannot know what type of list to return because its only parameter has no information about the return type. Hence, it can't possibly decide which type to create as a prototype. So no matter what, if you wanted to use common Load method, you would have to pass it a type like the above syntax.
For the Save method, you could use reflection to create the prototype in the static method, by obtaining the type from the first element, and then call the Save method from the prototype. So if you only need the Save method to be used as you like, that much is possible.
Ultimately, though, I think it would be a lot simpler to do something like this:
public static XElement Save(List<IBaseClass> list)
{
if (list is Temperature) {
// do temperature code
} else if (list is SomethingElse) {
// do something else
}
}
Anyway - like I said it's going to require reflection to make even the Save method work in this way. I'd just use the simple approach.
(original bad code removed)
If you don't really care about the format in which its saved, you're free to use serialisation (which uses reflection internally).
string SerialiseToString<T>(T source)
{
using (StringWriter sw = new StringWriter() && XmlSerializer xml = new XmlSerializer(typeof(OrderedItem)))
{
xml.Serializer(sw, source);
return sw.ToString();
}
}
If you want to incorporate it into a larger part of your XML file, the easiest way would be to parse this output and add it to yours. Alternatively, you could reflect the properties yourself.
If the shared part is the same, you can put it in BaseClass:
public static XElement Save(IEnumerable<BaseClass> list)
{
var root = new XElement("root");
foreach (var item in list)
{
item.Save(root);
}
return root;
}
Here, Save(XElement) is a virtual method, each type implements it.
Obviously, you can't do this with loading, you either have to know what type are you loading, or have some way of finding out which type are you loading.
I'll try to explain this the best I can. I'm having quite a bit of difficulty trying to figure out this logic.
Basically, I have a collection that includes thousands of objects which are each made up of a Parent and a Child property.
So, roughly, this:
public class MyObject{
public string Parent { get; set; }
public string Child { get; set; }
}
What I'm trying to figure out is how to build this out into a plain TreeView control. I need to build the relationships but I can't figure out how to because they can be mixed. I can probably explain this better with what the tree should look like:
So if I have the following items inside of my collection:
0. Parent: "A", Child: "B"
1. Parent: "B", Child: "C"
2. Parent: "B", Child: "D"
I would want my tree to look this like:
-A
--B
---C
-A
--B
---D
-B
--C
-B
--D
How can I do this in C#? I would need it to support up to N relationships as we have some branches I would expect to reach about 50 nodes deep.
UPDATE
This problem actually turned out to be considerably more complex than I originally realized, given the requirement of repeating the entire tree for each path. I've simply deleted the old code as I don't want to add any further confusion.
I do want to keep it on record that using a recursive data structure makes this easier:
public class MyRecursiveObject
{
public MyRecursiveObject Parent { get; set; }
public string Name { get; set; }
public List<MyRecursiveObject> Children { get; set; }
}
You'll see very clearly why this is easier after reading the implementation code below:
private void PopulateTree(IEnumerable<MyObject> items)
{
var groupedItems =
from i in items
group i by i.Parent into g
select new { Name = g.Key, Children = g.Select(c => c.Child) };
var lookup = groupedItems.ToDictionary(i => i.Name, i => i.Children);
foreach (string parent in lookup.Keys)
{
if (lookup.ContainsKey(parent))
AddToTree(lookup, Enumerable.Empty<string>(), parent);
}
}
private void AddToTree(Dictionary<string, IEnumerable<string>> lookup,
IEnumerable<string> path, string name)
{
IEnumerable<string> children;
if (lookup.TryGetValue(name, out children))
{
IEnumerable<string> newPath = path.Concat(new string[] { name });
foreach (string child in children)
AddToTree(lookup, newPath, child);
}
else
{
TreeNode parentNode = null;
foreach (string item in path)
parentNode = AddTreeNode(parentNode, item);
AddTreeNode(parentNode, name);
}
}
private TreeNode AddTreeNode(TreeNode parent, string name)
{
TreeNode node = new TreeNode(name);
if (parent != null)
parent.Nodes.Add(node);
else
treeView1.Nodes.Add(node);
return node;
}
First of all, I realized that the dictionary will contain keys for intermediate nodes as well as just the root nodes, so we don't need two recursive calls in the recursive AddToTree method in order to get the "B" nodes as roots; the initial walk in the PopulateTree method already does it.
What we do need to guard against is adding leaf nodes in the initial walk; using the data structure in question, these are detectable by checking whether or not there is a key in the parent dictionary. With a recursive data structure, this would be way easier: Just check for Parent == null. But, a recursive structure is not what we have, so the code above is what we have to use.
The AddTreeNode is mostly a utility method, so we don't have to keep repeating this null-checking logic later.
The real ugliness is in the second, recursive AddToTree method. Because we are trying to create a unique copy of every single subtree, we can't simply add a tree node and then recurse with that node as the parent. "A" only has one child here, "B", but "B" has two children, "C" and "D". There needs to be two copies of "A", but there's no way to know about that when "A" is originally passed to the AddToTree method.
So what we actually have to do is not create any nodes until the final stage, and store a temporary path, for which I've chosen IEnumerable<string> because it's immutable and therefore impossible to mess up. When there are more children to add, this method simply adds to the path and recurses; when there are no more children, it walks the entire saved path and adds a node for each.
This is extremely inefficient because we are now creating a new enumerable on every invocation of AddToTree. For large numbers of nodes, it is likely to chew up a lot of memory. This works, but it would be a lot more efficient with a recursive data structure. Using the example structure at the top, you wouldn't have to save the path at all or create the dictionary; when no children are left, simply walk up the path in a while loop using the Parent reference.
Anyway, I guess that's academic because this isn't a recursive object, but I thought it was worth pointing out anyway as something to keep in mind for future designs. The code above will produce exactly the results you want, I've gone ahead and tested it on a real TreeView.
UPDATE 2 - So it turns out that the version above is pretty brutal with respect to memory/stack, most likely a result of creating all those IEnumerable<string> instances. Although it's not great design, we can remove that particular issue by changing to a mutable List<string>. The following snippet shows the differences:
private void PopulateTree(IEnumerable<MyObject> items)
{
// Snip lookup-generation code - same as before ...
List<string> path = new List<string>();
foreach (string parent in lookup.Keys)
{
if (lookup.ContainsKey(parent))
AddToTree(lookup, path, parent);
}
}
private void AddToTree(Dictionary<string, IEnumerable<string>> lookup,
IEnumerable<string> path, string name)
{
IEnumerable<string> children;
if (lookup.TryGetValue(name, out children))
{
path.Add(name);
foreach (string child in children)
AddToTree(lookup, newPath, child);
path.Remove(name);
}
// Snip "else" block - again, this part is the same as before ...
}
like rubens, I tried both, but a little better I think A Generic Tree Collection
this tree collection got some nice functionality build-in to move around the tree, go read the whole article
sample with the link above
Static Class Module1
{
public static void Main()
{
Common.ITree<myObj> myTree = default(Common.ITree<myObj>);
myObj a = new myObj("a");
myObj b = new myObj("b");
myObj c = new myObj("c");
myObj d = new myObj("d");
myTree = Common.NodeTree<myObj>.NewTree;
myTree.InsertChild(a).InsertChild(b).InsertChild(c).Parent.Parent.InsertNext(a).InsertChild(b).InsertChild(d).Parent.Parent.InsertNext(b).InsertChild(c).Parent.InsertNext(b).InsertChild(d);
Console.WriteLine(myTree.ToStringRecursive);
Console.ReadKey();
}
}
Class myObj
{
public string text;
public myObj(string value)
{
text = value;
}
public override string ToString()
{
return text;
}
}
would be exactly what you just showed
-A
--B
---C
-A
--B
---D
-B
--C
-B
--D
If I understand this correctly, what you're trying to do is take one tree and transform it into another. The transformation essentially takes each non-leaf-node in the input tree and creates a node for it (and its descendants) in the output tree.
First off, you'll be happier if you design a data structure for your nodes that is genuinely recursive:
public class Node
{
public Node Parent { get; private set; }
public IEnumerable<Node> Children { get; private set; }
public bool HasChildren { get { return Children.Count() > 0; } }
public Node()
{
Children = new List<Node>();
}
}
Your MyObject class represents parent/child relationships between string values. As long as you're able to implement a FindChildren() method that returns the child values for a given parent value, using this class to rationalize the parent/child relationships is straightforward:
public string Value { get; set; }
public static Node Create(string parentKey)
{
Node n = new Node();
n.Value = parentKey;
foreach (string childKey in FindChildren(parentKey))
{
Node child = n.Children.Add(Node.Create(childKey));
child.Parent = n;
}
return n;
}
It's simple to implement a property that returns a node's descendants:
public IEnumerable<Node> Descendants
{
get
{
foreach (Node child in Children)
{
yield return child;
foreach (Node descendant in child.Descendants)
{
yield return descendant;
}
}
}
}
To add a Node to a TreeView, you need two methods. (Note that these aren't methods of the Node class!) I've made them overloads, but an argument can be made for giving them different names:
public void AddNode(Node n, TreeView tv)
{
TreeNode tn = tv.Nodes.Add(n.Value);
tn.Tag = n;
foreach (Node child in n.Children)
{
AddNode(child, tn);
}
}
public void AddNode(Node n, TreeNode parent)
{
TreeNode tn = parent.Nodes.Add(n.Value);
parent.Tag = n;
foreach (Node child in n.Children)
{
AddNode(child, tn);
}
}
I'm setting the Tag on each TreeNode so that you can find your way back to the original Node.
So to initialize your TreeView from a list of top-level parent keys, you need a method like this:
public void PopulateTreeView(IEnumerable<string> parents, TreeView t)
{
foreach (string parentKey in parents)
{
Node n = Node.Create(parentKey);
AddNode(n, t);
foreach (Node descendant in n.Descendants)
{
if (n.HasChildren)
{
AddNode(descendant, t);
}
}
}
}
Edit:
I didn't quite understand how your MyObject class was working; I think I do now, and I've edited this accordingly.
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.