#region Using's
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
#endregion Using's
internal static class Program
{
private static void Main() {
var tree = Tree.New(1);
tree.Add(2);
tree.Add(3);
tree.Children[0].Add(4);
tree.Children[1].Add(5);
foreach(var item in tree.Nodes()) {
Debug.Print(item.ToString());
}//for
foreach(var item in tree.Values()) {
Debug.Print(item.ToString());
}//for
}
}
[DebuggerDisplay("{ToString()}")]
[Serializable]
public sealed class Node<T>
{
#region Fields
private readonly IList<Node<T>> children;
#endregion Fields
#region Constructor(s)
public Node() {
children = new NodeCollection(this);
}
public Node(T value) : this() {
Value = value;
}
#endregion Constructor(s)
#region Properties
public Node<T> Parent { get; private set; }
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public IList<Node<T>> Children {
[DebuggerStepThrough]
get { return children; }
}
public T Value { get; set; }
#endregion Properties
#region Methods
public Node<T> Add(T value) {
var item = new Node<T>(value);
Children.Add(item);
return item;
}
#endregion Methods
#region Overrides
public override string ToString() {
return "<Node> {" + Value + "}";
}
#endregion Overrides
#region class NodeCollection
[Serializable]
private sealed class NodeCollection : Collection<Node<T>>
{
#region Fields
private readonly Node<T> owner;
#endregion Fields
#region Constructor(s)
public NodeCollection(Node<T> owner) {
if(owner == null) {
throw new ArgumentNullException("owner");
}//if
this.owner = owner;
}
#endregion Constructor(s)
#region Properties
private Node<T> Owner {
[DebuggerStepThrough]
get { return owner; }
}
#endregion Properties
#region Methods
private void AttachItem(Node<T> item) {
if(item == null) {
throw new ArgumentNullException("item");
}//if
item.Parent = Owner;
}
private void DetachItem(Node<T> item) {
if(item == null) {
throw new ArgumentNullException("item");
}//if
Debug.Assert(item.Parent == Owner, "item.Parent == Owner");
item.Parent = null;
}
private void ValidateItem(Node<T> item) {
if(item == null) {
throw new ArgumentNullException("item");
} else if(item.Parent != null) {
throw new InvalidOperationException("item.Parent != null");
}//if
}
#endregion Methods
#region Overrides
protected override void InsertItem(int index, Node<T> item) {
ValidateItem(item);
base.InsertItem(index, item);
AttachItem(item);
}
protected override void SetItem(int index, Node<T> item) {
ValidateItem(item);
DetachItem(this[index]);
base.SetItem(index, item);
AttachItem(item);
}
protected override void RemoveItem(int index) {
DetachItem(this[index]);
base.RemoveItem(index);
}
protected override void ClearItems() {
foreach(var item in Items) {
DetachItem(item);
}//for
base.ClearItems();
}
#endregion Overrides
}
#endregion class NodeCollection
}
public static class Tree
{
#region Methods
public static Node<T> New<T>(T value) {
return new Node<T>(value);
}
public static bool IsRoot<T>(Node<T> node) {
if(node == null) {
throw new ArgumentNullException("node");
}//if
return node.Parent == null;
}
public static IEnumerable<Node<T>> Nodes<T>(this Node<T> node) {
if(node == null) {
throw new ArgumentNullException("node");
}//if
return NodesIterator(node);
}
private static IEnumerable<Node<T>> NodesIterator<T>(Node<T> node) {
Debug.Assert(node != null, "node != null");
yield return node;
foreach(var item in NodesIterator(node.Children)) {
yield return item;
}//for
}
private static IEnumerable<Node<T>> NodesIterator<T>(IEnumerable<Node<T>> children) {
Debug.Assert(children != null, "children != null");
foreach(var child in children) {
foreach(var item in child.Nodes()) {
yield return item;
}//for
}//for
}
public static IEnumerable<T> Values<T>(this Node<T> root) {
if(root == null) {
throw new ArgumentNullException("root");
}//if
return from node in root.Nodes()
select node.Value;
}
#endregion Methods
}
// А вот и fluent-interface с тестом
using System.IO;
using System.Xml.Serialization;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
namespace Frontier.Framework.Core.Collections.Test
{
[TestFixture]
public class TreeTest
{
[Test]
public void CreateEmptyTreeAndCheckHasChilds()
{
ITree<int> root = TreeNode<int>
.RootNode("root", 1000);
Assert.IsFalse(root.HasChilds, "might not has a childs");
}
[Test]
public void CreateFullTreeAndCheck()
{
ITree<int> root = TreeNode<int>
.RootNode("root", 0)
.Begin
.Append("a1", 1)
.Append("a2", 2)
.Begin
.Append("b1", 1)
.Append("b2", 2)
.End
.Append("a3", 3)
.End;
Assert.That(1, Is.EqualTo(root["a1"].Value));
Assert.That(2, Is.EqualTo(root["a2"].Value));
Assert.That(3, Is.EqualTo(root["a3"].Value));
Assert.That(1, Is.EqualTo(root["a2"]["b1"].Value));
Assert.That(2, Is.EqualTo(root["a2"]["b2"].Value));
}
[Test]
public void CreateRoot()
{
TreeNode<int>
.RootNode("root", 1000);
}
[Test]
public void CreateRootAndCheck()
{
ITree<int> root = TreeNode<int>
.RootNode("root", 1000);
Assert.That("root", Is.EqualTo(root.Id));
Assert.That(1000, Is.EqualTo(root.Value));
}
[Test]
public void CreateRootAndEnumChilds()
{
ITree<int> root = TreeNode<int>
.RootNode("root", 1000)
.Begin
.Append("a1", 1)
.Append("a2", 2)
.Append("a3", 3)
.End;
int count = 0;
foreach (var node in root)
count++;
Assert.AreEqual(3, count);
}
[Test]
public void CreateRootUnnamedAndCheck()
{
ITree<int> root = TreeNode<int>
.RootNode(1000);
Assert.That("root", Is.EqualTo(root.Id));
}
[Test]
public void CreateSimpleTreeAndUseIndexerToCheck()
{
ITree<int> tree = TreeNode<int>
.RootNode("root", 0)
.Append("a1", 1)
.Append("a2", 2)
.Append("a3", 3);
int value;
Assert.IsTrue(tree.HasChilds);
value = tree.Value;
Assert.That(0, Is.EqualTo(value));
value = tree["a1"].Value;
Assert.That(1, Is.EqualTo(value));
value = tree["a2"].Value;
Assert.That(2, Is.EqualTo(value));
value = tree["a3"].Value;
Assert.That(3, Is.EqualTo(value));
}
[Test]
public void CreateSimpleTreeAndUseUnnamedIndexerToCheck()
{
ITree<int> tree = TreeNode<int>
.RootNode(0)
.Append(1)
.Append(2)
.Append(3);
int value;
Assert.IsTrue(tree.HasChilds);
value = tree.Value;
Assert.That(0, Is.EqualTo(value));
value = tree[0].Value;
Assert.That(1, Is.EqualTo(value));
value = tree[1].Value;
Assert.That(2, Is.EqualTo(value));
value = tree[2].Value;
Assert.That(3, Is.EqualTo(value));
}
[Test]
public void CreateTreeAndCheckItByUseIndexer()
{
ITree<int> root = TreeNode<int>
.RootNode("root", 1000);
int value = root["root"].Value;
Assert.That(1000, Is.EqualTo(value));
}
[Test]
public void CreateTreeAndInvokeToString()
{
ITree<int> root = TreeNode<int>
.RootNode("root", 1000);
var expected = "TreeNode<Int32>(\"root\")";
var actual = root.ToString();
Assert.AreEqual(expected, actual);
}
[Test, Category("Persistence"), Ignore]
public void SaveToXml()
{
ITree<int> root = TreeNode<int>
.RootNode("root", 1000)
.Begin
.Append("a1", 1)
.Append("a2", 2)
.Append("a3", 3)
.End;
string xml;
using (TextWriter writer = new StringWriter())
{
var serializer = new XmlSerializer(root.GetType());
serializer.Serialize(writer, root);
xml = writer.ToString();
}
Assert.Fail("Нихера не реализовано");
}
}
}