I have a custom class that gets some data from the web.
When I get this data I want to set it to the value of a property but when I do this unity crashes. The commented line generates the crash without this line everything works fine. See my code below:
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class GetDB
{
private readonly Main m;
private readonly string Url;
public string DBData {
get
{
if(DBData == null)
return null;
else
return DBData;
}
private set
{
DBData = value;
}
}
public GetDB(Main m, string url)
{
this.m = m;
this.Url = url;
}
public void GetServerData(){
m.StartCoroutine(GetText(Url, (result) =>{
this.DBData = result; //THIS LINE CRASHES UNITY
Debug.Log(result);
}));
}
IEnumerator GetText(string url, Action<string> result) {
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.SendWebRequest();
if(www.isNetworkError || www.isHttpError) {
Debug.Log(www.error);
}
else {
if (result != null)
result(www.downloadHandler.text);
}
}
}
How would I go about fixing this, and what exactly is happening here?
If anything is unclear let me know so I can clarify.
You have to use a backing field for the property:
string _dbData;
public string DBData
{
get
{
if(_dbData == null)
return null;
else
return _dbData;
}
private set
{
_dbData= value;
}
}
A property is just syntactic sugar for a getter and setter methods. So you can rewrite your property like:
public string GetDBData()
{
if(_dbData == null)
return null;
else
return _dbData;
}
public void SetDBData(string value)
{
_dbData = value;
}
The way you have implemented the property:
public void SetDBData(string value)
{
// you will never get out of here
SetDBData(value);
}
Properties act as accessors for variables. What is happening in your case is basically an endless loop - whenever somebody tries to get the value of your property, it keeps returning the property itself. Instead, you want a backing field _dbData:
private string _dbData;
public string DBData
{
get
{
return _dbData;
}
private set
{
_dbData = value;
}
}
Now your property controls the accesss to this field.
Your accessor can be really simplified.
Doing :
get
{
if(DBData == null)
return null;
else
return DBData;
}
Will provide exactly the same result than doing :
get
{
return DBData; //if DBData is null, it will return null
}
So, you can write your accessor that way :
public string DBData
{
get;
private set;
}
I've just started learning how to program and have been following along with this tutorial on graphs but I've run into some issues using the given
AddDirectedEdge(GraphNode<T> from, GraphNode<T> to, int cost)
It fails to build using the default from the tutorial, for example
web.AddDirectedEdge("People.aspx", "Privacy.htm"); // People -> Privacy
This gives the error "No overload for method 'AddDirectedEdge' takes 2 arguments". Adding an integer as a third argument does not help either, it just gives another error "Argument#: cannot convert from 'string' to 'GraphTest.GraphNode< string>'"
I'm not sure how to fix this, any help/insight regarding it would be appreciated. For ease of viewing the graph and graph node classes are shown below (these are all available through the above link as well):
public class GraphNode<T> : Node<T>
{
private List<int> costs;
public GraphNode() : base() { }
public GraphNode(T value) : base(value) { }
public GraphNode(T value, NodeList<T> neighbors) : base(value, neighbors) { }
new public NodeList<T> Neighbors
{
get
{
if (base.Neighbors == null)
base.Neighbors = new NodeList<T>();
return base.Neighbors;
}
}
public List<int> Costs
{
get
{
if (costs == null)
costs = new List<int>();
return costs;
}
}
}
.
public class Graph<T> : IEnumerable<T>
{
private NodeList<T> nodeSet;
public Graph() : this(null) { }
public Graph(NodeList<T> nodeSet)
{
if (nodeSet == null)
this.nodeSet = new NodeList<T>();
else
this.nodeSet = nodeSet;
}
public void AddNode(GraphNode<T> node)
{
// adds a node to the graph
nodeSet.Add(node);
}
public void AddNode(T value)
{
// adds a node to the graph
nodeSet.Add(new GraphNode<T>(value));
}
public void AddDirectedEdge(GraphNode<T> from, GraphNode<T> to, int cost)
{
from.Neighbors.Add(to);
from.Costs.Add(cost);
}
public void AddUndirectedEdge(GraphNode<T> from, GraphNode<T> to, int cost)
{
from.Neighbors.Add(to);
from.Costs.Add(cost);
to.Neighbors.Add(from);
to.Costs.Add(cost);
}
public bool Contains(T value)
{
return nodeSet.FindByValue(value) != null;
}
public bool Remove(T value)
{
// first remove the node from the nodeset
GraphNode<T> nodeToRemove = (GraphNode<T>)nodeSet.FindByValue(value);
if (nodeToRemove == null)
// node wasn't found
return false;
// otherwise, the node was found
nodeSet.Remove(nodeToRemove);
// enumerate through each node in the nodeSet, removing edges to this node
foreach (GraphNode<T> gnode in nodeSet)
{
int index = gnode.Neighbors.IndexOf(nodeToRemove);
if (index != -1)
{
// remove the reference to the node and associated cost
gnode.Neighbors.RemoveAt(index);
gnode.Costs.RemoveAt(index);
}
}
return true;
}
public NodeList<T> Nodes
{
get
{
return nodeSet;
}
}
public int Count
{
get { return nodeSet.Count; }
}
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
throw new NotImplementedException();
}
}
Well, obviously it is complaining about type mismatch:
you are supplying string type instead of GraphNode<T>.
Instead you should call it as:
web.AddDirectedEdge(new GraphNode("People.aspx"), new GraphNode("Privacy.htm"), 1);
where 1 is a cost, which is required, or
var ppl = new GraphNode("People.aspx");
var prv = new GraphNode("Privacy.htm");
web.AddDirectedEdge(ppl, prv, 1);
if you like to reuse nodes further in code.
As a side note, it seems you are making some trivial mistakes. Before making it further I strongly recommend you to take at least basic course of C#. There is plenty of then available for free in the Web, this for example.
I have class with two properties which are Lists, one of it contents int - that's IDs of objects from second List. I override setters and getters to save them agreeable with each other. But when I add some this to list they are not synchronized. How to make them synchronized?
Here is code
public class Item
{
private List<Operation> _operations = new List<Operation>();
private List<int> _operationsID = new List<int>();
public List<Operation> operations
{
get { return this._operations; }
set
{
this._operations = value;
if (value != null)
{
foreach (Operation oper in value)
{
this._operationsID.Add(oper.ID);
}
}
}
}
public List<int> operationsID
{
get { return this._operationsID; }
set
{
this._operationsID = value;
if (value != null)
{
foreach (int operID in value)
{
this._operations.Add(new Operation(operID));
}
}
}
}
}
Should I override List.Add if so, how it can me made?
It is a bit unclear what it is you are trying to do, but basically it seems like you need to encapsulate those lists so the user can't work on them directly (and get them out of sync). You do this by not exposing the lists to the user. Basically you are trying to keep the items contained to the user so whenever they work on your set of items, they would be forced to go through this class and the functions that class exposes. Your only issue then is to find out what to expose to the user and in what manner.
public class Item {
private List<Operation> _operations = new List<Operation>();
private List<int> _operationsID = new List<int>();
public void addOperation(Operation o) {
_operations.Add(o);
_operationsID.Add(getIdentifier(o));
}
public void removeOperation(Operation o) {
_operations.Remove(o);
_operationsID.Remove(getIdentifier(o));
}
public void clear() {
_operations.clear();
_operationsID.clear();
}
public void findOperationMatching(Foobar foo) {
//
}
private int getIdentifier(Operation id) {
//
}
}
You have to clear previous list content before calling Add method:
public List<Operation> operations
{
get { return this._operations; }
set
{
this._operations = value;
if (value != null)
{
this._operationsID.Clear();
foreach (Operation oper in value)
{
this._operationsID.Add(oper.ID);
}
}
else
{
this._operationsID = null;
}
}
}
But to be honest, I don't think it's a good idea to keep these things in two different lists. Why don't you use Dictionary<int, Operation>?
It's a bad idea to try to manage two versions of the truth. If it were me, I'd expose one List<Operation> that callers can Add/Remove, and a second IEnumerable<int> which simply exposes the ID's of the operations:
public List<Operation> Operations { get; set; }
public IEnumerable<int> OperationIDs
{
get
{
return Operations.Select(op => op.OperationID);
}
}
This way, callers can use the Operations list to do whatever they need to do (Add, Remove, Count, etc). The OperationIDs is now not a second property that people can work with; instead it only reflects information that is in the Operations property.
been struggling with this for a couple of days now and still stumped.
i have a data structure that starts with containers that can hold other containers, and eventually leaf nodes. i'm looking for a way of being to iterate thru elements of a type directly, without pulling them into another collection so i can operate on them in place and then save the resulting structure out.
The code below is a noddy version, and if you set a break point on each findElements function you'll see that it drops out without recursing. this is on mono and ms runtimes, so i'm sure it's me not getting something rather than a bug ;)
also, the function should ideally be
IEnumerable<object> findElements<T>();
but i can't get the cast to work on this line then :
if (this is T) yield return this;
should ideally be
if (this is T) yield return (T)this;
thanks for any suggestions / clarity / light
using System;
using System.Collections.Generic;
using System.Text;
namespace covariantTest {
class MainClass {
public static void Main(string[] args) {
Console.WriteLine("Starting");
Document root = new Document("rooty");
root.Children.Add(new File("file 1"));
root.Children.Add(new File("file 2"));
Document doc2 = new Document("doc2");
File file3 = new File("file 3");
file3.Lines.Add(new Line("line 1 file 3"));
file3.Lines.Add(new Line("line 2 file 3"));
doc2.Children.Add(file3);
File file4 = new File("file 4");
file4.Lines.Add(new Line("stuff about stuff"));
file4.Lines.Add(new Line("Babylon n ting"));
file4.Lines.Add(new Line("last line"));
doc2.Children.Add(file4);
root.Children.Add(doc2);
// find the lines
foreach (object obj in root.findElements<Line>()) {
Line line = obj as Line;
Console.WriteLine(line.Contents);
}
// done
Console.WriteLine("Press enter to finish");
Console.ReadLine();
}
}// Main
#region classes
public class Line : ISearchable {
private string _contents = string.Empty;
public Line() {}
public Line(string contents) {
_contents = contents;
}
#region properties
public string Contents {
get { return _contents; }
set { _contents = value; }
}
#endregion properties
public IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
}
}// Line
public class File : Container {
private List<Line> _lines = new List<Line>();
public File() : base() {}
public File(string name) : base(name) {}
#region properties
public List<Line> Lines {
get { return _lines; }
set { _lines = value; }
}
#endregion properties
public override IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
else base.findElements<T>();
}
}// File
public class Document : Container {
public Document() : base() {}
public Document(string name) : base(name) {}
public override IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
else base.findElements<T>();
}
}// Document
public abstract class Container : ISearchable {
private string _name = string.Empty;
private List<Container> _children = new List<Container>();
public Container() {}
public Container(string name) {
_name = name;
}
#region properties
public string Name {
get { return _name; }
set { _name = value; }
}
public List<Container> Children {
get { return _children; }
set { _children = value; }
}
#endregion properties
#region interfaces
public virtual IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
foreach (Container item in _children) {
item.findElements<T>();
}
}
#endregion interfaces
}// Container
#endregion classes
#region interfaces
public interface ISearchable {
IEnumerable<object> findElements<T>();
}
#endregion interfaces
}// namespace
I think you code is a bit complex, but I may have bad understood you target.
Anyway, here is a sample to scan in a "flat-fashion" your tree. I also used a very small code just to show-how, but obviously you have to work on.
namespace ConsoleApplication3
{
//this is a node of your tree, but you may add whatever you want inside
class Item
{
public List<Item> Items { get; set; }
}
class Program
{
static void Main(string[] args)
{
//define the tree structure
var tree = new Item();
// (complete your tree-structrure)
//define the action delegate
Action<Item> action = (item) => Console.WriteLine(item);
//scan the hierarchy
Scan(
tree,
typeof(Item),
action);
}
//here is the flat-scan function, the "typeToFind" here is just
//for example and have very little sense to be in
static void Scan(
Item startItem,
Type typeToFind,
Action<Item> action)
{
var temp = new List<Item>();
temp.Add(startItem);
while (temp.Count > 0)
{
var item = temp[0];
temp.RemoveAt(0);
if (typeToFind.IsInstanceOfType(item))
{
action(item);
}
temp.AddRange(item.Items);
}
}
}
}
Hope this helps. Cheers.
How do you expect it to work? If I understand it correctly, then yield does not work when called from another function (so if you call base.findElements then you ain't gonna get any results from it). I suggest rewriting it without yield. To avoid creating many lists, I would pass list as a parameter, in such a way:
public interface ISearchable {
void doFindElements<T>(List<T> putThemHere);
}
// this is extender for syntactical sugar
public static class SearchableExtender
{
public static IEnumerable<T> findElements<T>(this ISearchable obj)
{
List<T> result = new List<T>();
obj.doFindElements(result);
return result;
}
}
public abstract class Container : ISearchable {
...
public virtual void doFindElements<T>(List<T> putThemHere)
{
if (this is T) putThemHere.Add(this);
foreach (Container item in _children) { item.doFindElements(putThemHere); }
}
...
}
By the way, you don't need to override doFindElements in Document, inherited version from Container will do OK, as "this" would mean a Document here. Implementation of File is completely wrong. Base Container class would not see Lines property and instead would use empty Children property. There are two ways to work around this:
You need to kill _lines and instead work with _children from the base class (for example, you can make Collection<Line> descendent that would be a wrapper around _children class by overriding InsertItem, SetItem, RemoveItem and ClearItems and calling appropriate methods of _children).
Remove _children from Container, instead make virtual abstract function IEnumerable GetChildElements() that each descendent would implement and return its own List<> of child elements. In doFindElements you would call that function instead of _children. You can even make second base class, like UntypedContainer: Container that would declare List<Container> _children, override GetChildElements() to return _children and inherit Document from it. File would still be inherited from simple Container, as it have its own children list.
The second way is simpler and better.
I was looking for a tree or graph data structure in C#, but I guess there isn't one provided. An Extensive Examination of Data Structures Using C# 2.0 a bit about why. Is there a convenient library which is commonly used to provide this functionality? Perhaps through a strategy pattern to solve the issues presented in the article.
I feel a bit silly implementing my own tree, just as I would implementing my own ArrayList.
I just want a generic tree which can be unbalanced. Think of a directory tree. C5 looks nifty, but their tree structures seem to be implemented as balanced red-black trees better suited to search than representing a hierarchy of nodes.
My best advice would be that there is no standard tree data structure because there are so many ways you could implement it that it would be impossible to cover all bases with one solution. The more specific a solution, the less likely it is applicable to any given problem. I even get annoyed with LinkedList - what if I want a circular linked list?
The basic structure you'll need to implement will be a collection of nodes, and here are some options to get you started. Let's assume that the class Node is the base class of the entire solution.
If you need to only navigate down the tree, then a Node class needs a List of children.
If you need to navigate up the tree, then the Node class needs a link to its parent node.
Build an AddChild method that takes care of all the minutia of these two points and any other business logic that must be implemented (child limits, sorting the children, etc.)
delegate void TreeVisitor<T>(T nodeData);
class NTree<T>
{
private T data;
private LinkedList<NTree<T>> children;
public NTree(T data)
{
this.data = data;
children = new LinkedList<NTree<T>>();
}
public void AddChild(T data)
{
children.AddFirst(new NTree<T>(data));
}
public NTree<T> GetChild(int i)
{
foreach (NTree<T> n in children)
if (--i == 0)
return n;
return null;
}
public void Traverse(NTree<T> node, TreeVisitor<T> visitor)
{
visitor(node.data);
foreach (NTree<T> kid in node.children)
Traverse(kid, visitor);
}
}
Simple recursive implementation...
< 40 lines of code...
You just need to keep a reference to the root of the tree outside of the class,
or wrap it in another class, maybe rename to TreeNode??
Here's mine, which is very similar to Aaron Gage's, just a little more conventional, in my opinion. For my purposes, I haven't ran into any performance issues with List<T>. It would be easy enough to switch to a LinkedList if needed.
namespace Overby.Collections
{
public class TreeNode<T>
{
private readonly T _value;
private readonly List<TreeNode<T>> _children = new List<TreeNode<T>>();
public TreeNode(T value)
{
_value = value;
}
public TreeNode<T> this[int i]
{
get { return _children[i]; }
}
public TreeNode<T> Parent { get; private set; }
public T Value { get { return _value; } }
public ReadOnlyCollection<TreeNode<T>> Children
{
get { return _children.AsReadOnly(); }
}
public TreeNode<T> AddChild(T value)
{
var node = new TreeNode<T>(value) {Parent = this};
_children.Add(node);
return node;
}
public TreeNode<T>[] AddChildren(params T[] values)
{
return values.Select(AddChild).ToArray();
}
public bool RemoveChild(TreeNode<T> node)
{
return _children.Remove(node);
}
public void Traverse(Action<T> action)
{
action(Value);
foreach (var child in _children)
child.Traverse(action);
}
public IEnumerable<T> Flatten()
{
return new[] {Value}.Concat(_children.SelectMany(x => x.Flatten()));
}
}
}
Yet another tree structure:
public class TreeNode<T> : IEnumerable<TreeNode<T>>
{
public T Data { get; set; }
public TreeNode<T> Parent { get; set; }
public ICollection<TreeNode<T>> Children { get; set; }
public TreeNode(T data)
{
this.Data = data;
this.Children = new LinkedList<TreeNode<T>>();
}
public TreeNode<T> AddChild(T child)
{
TreeNode<T> childNode = new TreeNode<T>(child) { Parent = this };
this.Children.Add(childNode);
return childNode;
}
... // for iterator details see below link
}
Sample usage:
TreeNode<string> root = new TreeNode<string>("root");
{
TreeNode<string> node0 = root.AddChild("node0");
TreeNode<string> node1 = root.AddChild("node1");
TreeNode<string> node2 = root.AddChild("node2");
{
TreeNode<string> node20 = node2.AddChild(null);
TreeNode<string> node21 = node2.AddChild("node21");
{
TreeNode<string> node210 = node21.AddChild("node210");
TreeNode<string> node211 = node21.AddChild("node211");
}
}
TreeNode<string> node3 = root.AddChild("node3");
{
TreeNode<string> node30 = node3.AddChild("node30");
}
}
BONUS
See fully-fledged tree with:
iterator
searching
Java/C#
https://github.com/gt4dev/yet-another-tree-structure
The generally excellent C5 Generic Collection Library has several different tree-based data structures, including sets, bags and dictionaries. Source code is available if you want to study their implementation details. (I have used C5 collections in production code with good results, although I haven't used any of the tree structures specifically.)
See https://github.com/YaccConstructor/QuickGraph (previously http://quickgraph.codeplex.com/)
QuickGraph provides generic directed/undirected graph data structures and algorithms for .NET 2.0 and up. QuickGraph comes with algorithms such as depth-first search, breadth-first search, A* search, shortest path, k-shortest path, maximum flow, minimum spanning tree, least common ancestors, etc... QuickGraph supports MSAGL, GLEE, and Graphviz to render the graphs, serialization to GraphML, etc.
Here's my own:
class Program
{
static void Main(string[] args)
{
var tree = new Tree<string>()
.Begin("Fastfood")
.Begin("Pizza")
.Add("Margherita")
.Add("Marinara")
.End()
.Begin("Burger")
.Add("Cheese burger")
.Add("Chili burger")
.Add("Rice burger")
.End()
.End();
tree.Nodes.ForEach(p => PrintNode(p, 0));
Console.ReadKey();
}
static void PrintNode<T>(TreeNode<T> node, int level)
{
Console.WriteLine("{0}{1}", new string(' ', level * 3), node.Value);
level++;
node.Children.ForEach(p => PrintNode(p, level));
}
}
public class Tree<T>
{
private Stack<TreeNode<T>> m_Stack = new Stack<TreeNode<T>>();
public List<TreeNode<T>> Nodes { get; } = new List<TreeNode<T>>();
public Tree<T> Begin(T val)
{
if (m_Stack.Count == 0)
{
var node = new TreeNode<T>(val, null);
Nodes.Add(node);
m_Stack.Push(node);
}
else
{
var node = m_Stack.Peek().Add(val);
m_Stack.Push(node);
}
return this;
}
public Tree<T> Add(T val)
{
m_Stack.Peek().Add(val);
return this;
}
public Tree<T> End()
{
m_Stack.Pop();
return this;
}
}
public class TreeNode<T>
{
public T Value { get; }
public TreeNode<T> Parent { get; }
public List<TreeNode<T>> Children { get; }
public TreeNode(T val, TreeNode<T> parent)
{
Value = val;
Parent = parent;
Children = new List<TreeNode<T>>();
}
public TreeNode<T> Add(T val)
{
var node = new TreeNode<T>(val, this);
Children.Add(node);
return node;
}
}
Output:
Fastfood
Pizza
Margherita
Marinara
Burger
Cheese burger
Chili burger
Rice burger
I have a little extension to the solutions.
Using a recursive generic declaration and a deriving subclass, you can better concentrate on your actual target.
Notice, it’s different from a non generic implementation, you don’t need to cast 'node' to 'NodeWorker'.
Here's my example:
public class GenericTree<T> where T : GenericTree<T> // recursive constraint
{
// no specific data declaration
protected List<T> children;
public GenericTree()
{
this.children = new List<T>();
}
public virtual void AddChild(T newChild)
{
this.children.Add(newChild);
}
public void Traverse(Action<int, T> visitor)
{
this.traverse(0, visitor);
}
protected virtual void traverse(int depth, Action<int, T> visitor)
{
visitor(depth, (T)this);
foreach (T child in this.children)
child.traverse(depth + 1, visitor);
}
}
public class GenericTreeNext : GenericTree<GenericTreeNext> // concrete derivation
{
public string Name {get; set;} // user-data example
public GenericTreeNext(string name)
{
this.Name = name;
}
}
static void Main(string[] args)
{
GenericTreeNext tree = new GenericTreeNext("Main-Harry");
tree.AddChild(new GenericTreeNext("Main-Sub-Willy"));
GenericTreeNext inter = new GenericTreeNext("Main-Inter-Willy");
inter.AddChild(new GenericTreeNext("Inter-Sub-Tom"));
inter.AddChild(new GenericTreeNext("Inter-Sub-Magda"));
tree.AddChild(inter);
tree.AddChild(new GenericTreeNext("Main-Sub-Chantal"));
tree.Traverse(NodeWorker);
}
static void NodeWorker(int depth, GenericTreeNext node)
{ // a little one-line string-concatenation (n-times)
Console.WriteLine("{0}{1}: {2}", String.Join(" ", new string[depth + 1]), depth, node.Name);
}
Try this simple sample.
public class TreeNode<TValue>
{
#region Properties
public TValue Value { get; set; }
public List<TreeNode<TValue>> Children { get; private set; }
public bool HasChild { get { return Children.Any(); } }
#endregion
#region Constructor
public TreeNode()
{
this.Children = new List<TreeNode<TValue>>();
}
public TreeNode(TValue value)
: this()
{
this.Value = value;
}
#endregion
#region Methods
public void AddChild(TreeNode<TValue> treeNode)
{
Children.Add(treeNode);
}
public void AddChild(TValue value)
{
var treeNode = new TreeNode<TValue>(value);
AddChild(treeNode);
}
#endregion
}
I created a Node<T> class that could be helpful for other people. The class has properties like:
Children
Ancestors
Descendants
Siblings
Level of the node
Parent
Root
Etc.
There is also the possibility to convert a flat list of items with an Id and a ParentId to a tree. The nodes holds a reference to both the children and the parent, so that makes iterating nodes quite fast.
There is the now released .NET codebase: specifically the code for a SortedSet that implements a red-black tree: sortedset.cs
This is, however, a balanced tree structure. So my answer is more a reference to what I believe is the only native tree-structure in the .NET core library.
I've completed the code that Berezh has shared.
public class TreeNode<T> : IEnumerable<TreeNode<T>>
{
public T Data { get; set; }
public TreeNode<T> Parent { get; set; }
public ICollection<TreeNode<T>> Children { get; set; }
public TreeNode(T data)
{
this.Data = data;
this.Children = new LinkedList<TreeNode<T>>();
}
public TreeNode<T> AddChild(T child)
{
TreeNode<T> childNode = new TreeNode<T>(child) { Parent = this };
this.Children.Add(childNode);
return childNode;
}
public IEnumerator<TreeNode<T>> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
}
public class TreeNodeEnum<T> : IEnumerator<TreeNode<T>>
{
int position = -1;
public List<TreeNode<T>> Nodes { get; set; }
public TreeNode<T> Current
{
get
{
try
{
return Nodes[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public TreeNodeEnum(List<TreeNode<T>> nodes)
{
Nodes = nodes;
}
public void Dispose()
{
}
public bool MoveNext()
{
position++;
return (position < Nodes.Count);
}
public void Reset()
{
position = -1;
}
}
I have added a complete solution and example using the NTree class above. I also added the "AddChild" method...
public class NTree<T>
{
public T data;
public LinkedList<NTree<T>> children;
public NTree(T data)
{
this.data = data;
children = new LinkedList<NTree<T>>();
}
public void AddChild(T data)
{
var node = new NTree<T>(data) { Parent = this };
children.AddFirst(node);
}
public NTree<T> Parent { get; private set; }
public NTree<T> GetChild(int i)
{
foreach (NTree<T> n in children)
if (--i == 0)
return n;
return null;
}
public void Traverse(NTree<T> node, TreeVisitor<T> visitor, string t, ref NTree<T> r)
{
visitor(node.data, node, t, ref r);
foreach (NTree<T> kid in node.children)
Traverse(kid, visitor, t, ref r);
}
}
public static void DelegateMethod(KeyValuePair<string, string> data, NTree<KeyValuePair<string, string>> node, string t, ref NTree<KeyValuePair<string, string>> r)
{
string a = string.Empty;
if (node.data.Key == t)
{
r = node;
return;
}
}
Using it
NTree<KeyValuePair<string, string>> ret = null;
tree.Traverse(tree, DelegateMethod, node["categoryId"].InnerText, ref ret);
There is also the possibility to use XML with LINQ:
Create XML tree in C# (LINQ to XML)
XML is the most mature and flexible solution when it comes to using trees and LINQ provides you with all the tools that you need.
The configuration of your tree also gets much cleaner and user-friendly as you can simply use an XML file for the initialization.
If you need to work with objects, you can use XML serialization:
XML serialization
Most trees are formed by the data you are processing.
Say you have a person class that includes details of someone’s
parents, would you rather have the tree structure as part of your
“domain class”, or use a separate tree class that contained links to
your person objects? Think about a simple operation like getting all
the grandchildren of a person, should this code be in the person
class, or should the user of the person class have to know about a
separate tree class?
Another example is a parse tree in a compiler…
Both of these examples show that the concept of a tree is part of the domain of the data and using a separate general-purpose tree at least doubles the number of objects that are created as well as making the API harder to program again.
We want a way to reuse the standard tree operations, without having to reimplement them for all trees, while at the same time, not having to use a standard tree class. Boost has tried to solve this type of problem for C++, but I am yet to see any effect for .NET to get it adapted.
If you are going to display this tree on the GUI, you can use TreeView and TreeNode. (I suppose technically you can create a TreeNode without putting it on a GUI, but it does have more overhead than a simple homegrown TreeNode implementation.)
Here is my implementation of a BST:
class BST
{
public class Node
{
public Node Left { get; set; }
public object Data { get; set; }
public Node Right { get; set; }
public Node()
{
Data = null;
}
public Node(int Data)
{
this.Data = (object)Data;
}
public void Insert(int Data)
{
if (this.Data == null)
{
this.Data = (object)Data;
return;
}
if (Data > (int)this.Data)
{
if (this.Right == null)
{
this.Right = new Node(Data);
}
else
{
this.Right.Insert(Data);
}
}
if (Data <= (int)this.Data)
{
if (this.Left == null)
{
this.Left = new Node(Data);
}
else
{
this.Left.Insert(Data);
}
}
}
public void TraverseInOrder()
{
if(this.Left != null)
this.Left.TraverseInOrder();
Console.Write("{0} ", this.Data);
if (this.Right != null)
this.Right.TraverseInOrder();
}
}
public Node Root { get; set; }
public BST()
{
Root = new Node();
}
}
Tree With Generic Data
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
public class Tree<T>
{
public T Data { get; set; }
public LinkedList<Tree<T>> Children { get; set; } = new LinkedList<Tree<T>>();
public Task Traverse(Func<T, Task> actionOnNode, int maxDegreeOfParallelism = 1) => Traverse(actionOnNode, new SemaphoreSlim(maxDegreeOfParallelism, maxDegreeOfParallelism));
private async Task Traverse(Func<T, Task> actionOnNode, SemaphoreSlim semaphore)
{
await actionOnNode(Data);
SafeRelease(semaphore);
IEnumerable<Task> tasks = Children.Select(async input =>
{
await semaphore.WaitAsync().ConfigureAwait(false);
try
{
await input.Traverse(actionOnNode, semaphore).ConfigureAwait(false);
}
finally
{
SafeRelease(semaphore);
}
});
await Task.WhenAll(tasks);
}
private void SafeRelease(SemaphoreSlim semaphore)
{
try
{
semaphore.Release();
}
catch (Exception ex)
{
if (ex.Message.ToLower() != "Adding the specified count to the semaphore would cause it to exceed its maximum count.".ToLower())
{
throw;
}
}
}
public async Task<IEnumerable<T>> ToList()
{
ConcurrentBag<T> lst = new ConcurrentBag<T>();
await Traverse(async (data) => lst.Add(data));
return lst;
}
public async Task<int> Count() => (await ToList()).Count();
}
Unit Tests
using System.Threading.Tasks;
using Xunit;
public class Tree_Tests
{
[Fact]
public async Task Tree_ToList_Count()
{
Tree<int> head = new Tree<int>();
Assert.NotEmpty(await head.ToList());
Assert.True(await head.Count() == 1);
// child
var child = new Tree<int>();
head.Children.AddFirst(child);
Assert.True(await head.Count() == 2);
Assert.NotEmpty(await head.ToList());
// grandson
child.Children.AddFirst(new Tree<int>());
child.Children.AddFirst(new Tree<int>());
Assert.True(await head.Count() == 4);
Assert.NotEmpty(await head.ToList());
}
[Fact]
public async Task Tree_Traverse()
{
Tree<int> head = new Tree<int>() { Data = 1 };
// child
var child = new Tree<int>() { Data = 2 };
head.Children.AddFirst(child);
// grandson
child.Children.AddFirst(new Tree<int>() { Data = 3 });
child.Children.AddLast(new Tree<int>() { Data = 4 });
int counter = 0;
await head.Traverse(async (data) => counter += data);
Assert.True(counter == 10);
counter = 0;
await child.Traverse(async (data) => counter += data);
Assert.True(counter == 9);
counter = 0;
await child.Children.First!.Value.Traverse(async (data) => counter += data);
Assert.True(counter == 3);
counter = 0;
await child.Children.Last!.Value.Traverse(async (data) => counter += data);
Assert.True(counter == 4);
}
}
I don't like a tree aproach. It gets things overcomplicated including search or dril-down or even ui controls populating.
I would suggest to use a very simple approach with IDictionary<TChild, TParent>. This also allows to have no connections between nodes or levels.
In case you need a rooted tree data structure implementation that uses less memory, you can write your Node class as follows (C++ implementation):
class Node {
Node* parent;
int item; // depending on your needs
Node* firstChild; //pointer to left most child of node
Node* nextSibling; //pointer to the sibling to the right
}