I am confused as to exactly how classes inherit methods from each other. I already understand inheritance from base classes, there is however, certain code from an example that I do not understand. It involves searching a Binary tree and I could not find any resources that better explain how the code is inherited.
My aim is to understand it so that I can use it to also searched a linkedlist.
If any one can refer me to any relevant literature that explains this particular area I would be grateful.
I have highlighted the code section that I dont really yet understand how it is inhertied. The specific section is posted first:
public Company Read(string bezeichnung)
{
return stri.Search(new Company() { Bezeichnung = bezeichnung });
}
Entire program:
using System;
using System.IO;
using System.Text;
using System.Net;
namespace CompanySearch
{
class Program
{
static void Main(string[] args)
{
StreamReader r = new StreamReader(#"C:\Users\chris\Desktop\algo\fuckit\unternehmen.csv", Encoding.Default);
Companies stri2 = new Companies(r);
while (true)
{
Console.Write("Unternehmensbezeichnung eingeben: ");
string name = Console.ReadLine();
if (string.IsNullOrEmpty(name))
break;
//Company konk = stri2.Read(name);
Company konk = new Company();
konk = stri2.Read(name);
if (konk == null)
Console.WriteLine("Unternehmen nicht gefunden!");
else
Console.WriteLine(konk + "\n");
}
}
}
public class Companies
{
private BinaryTree<Company> stri = new BinaryTree<Company>();
public Companies(StreamReader rp)
{
// Spaltenüberschriften auslesen
//var tokens = rp.ReadLine().Split(new char[] { ';' });
//if (tokens.Length != 3)
// throw new ArgumentException("More than 3 columns in company file");
string line;
while ((line = rp.ReadLine()) != null)
{
var tokens = line.Split(new char[]{';'});
//tokens = line.Split(new char[] { ';' });
stri.Add(new Company()
{Bezeichnung = tokens[0], Branche = tokens[1], Ort = tokens[2]});
}
rp.Close();
}
public Company Read(string bezeichnung)
{
return stri.Search(new Company()
{Bezeichnung = bezeichnung});
}
}
public class Company : IComparable<Company>
{
public string Bezeichnung
{
get;
set;
}
public string Branche
{
get;
set;
}
public string Ort
{
get;
set;
}
public int CompareTo(Company other)
{
return Bezeichnung.CompareTo(other.Bezeichnung);
}
public override string ToString()
{
return string.Format("Bezeichnung: {0}\tBranche: {1}\tOrt: {2}", Bezeichnung, Branche, Ort);
}
}
public enum TraverseModeEnum
{
PreOrder,
PostOrder,
InOrder,
ReverseInOrder
}
public class BinaryTree<T>
where T : IComparable<T>
{
private sealed class Node<TNode>
where TNode : IComparable<TNode> // TNode muss IComparable implementieren
{
public TNode Item
{
get;
set;
}
public Node<TNode> Left
{
get;
set;
}
public Node<TNode> Right
{
get;
set;
}
public int CompareTo(TNode other)
{
return Item.CompareTo(other);
}
}
private Node<T> root;
public int Count
{
get;
private set;
}
public TraverseModeEnum TraverseMode
{
get;
set;
}
public BinaryTree()
{
TraverseMode = TraverseModeEnum.PreOrder;
}
public void Add(T item)
{
if (root == null)
root = new Node<T>()
{Item = item};
else
addTo(root, item);
Count++;
}
public void AddRange(T[] items)
{
foreach (var item in items)
Add(item);
}
private void addTo(Node<T> node, T item)
{
if (item.CompareTo(node.Item) < 0)
{
if (node.Left == null)
node.Left = new Node<T>()
{Item = item};
else
addTo(node.Left, item);
}
else
{
if (node.Right == null)
node.Right = new Node<T>()
{Item = item};
else
addTo(node.Right, item);
}
}
public bool Contains(T item)
{
Node<T> node = root;
while (node != null)
{
int c = node.Item.CompareTo(item);
if (c == 0)
return true;
if (c > 0)
node = node.Left;
else
node = node.Right;
}
return false;
}
public T Search(T item)
{
Node<T> node = root;
while (node != null)
{
int c = node.Item.CompareTo(item);
if (c == 0)
return node.Item;
if (c > 0)
node = node.Left;
else
node = node.Right;
}
return default (T);
}
public void Clear()
{
root = null;
Count = 0;
}
public override string ToString()
{
string s = "";
int level = 0;
traverse(root, level, ref s);
return s;
}
private void traverse(Node<T> node, int level, ref string s)
{
if (node == null)
return;
bool reverse = TraverseMode == TraverseModeEnum.ReverseInOrder;
if (TraverseMode == TraverseModeEnum.PreOrder)
s += "".PadLeft(level, ' ') + node.Item.ToString() + "\n";
traverse(reverse ? node.Right : node.Left, level + 2, ref s);
if (TraverseMode == TraverseModeEnum.InOrder || TraverseMode == TraverseModeEnum.ReverseInOrder)
s += "".PadLeft(level, ' ') + node.Item.ToString() + "\n";
traverse(reverse ? node.Left : node.Right, level + 2, ref s);
if (TraverseMode == TraverseModeEnum.PostOrder)
s += "".PadLeft(level, ' ') + node.Item.ToString() + "\n";
}
}
}
The class BinaryTree<T> down in the code demands that T must implement IComparable<T>. Lots of list-ish classes make similar demands. If a type implements IComparable<T> it means two instances of a class can be compared to each other with the ComparetTo( T t1, T t2 ) method. This method returns an indication of which T is greater than, less than, or equal to the other. Realize that the greater than, less than, or equal to is entirely up to the type that implements the interface. It's principally used for sorting or otherwise locating things in a tree, list, or other structure based on the comparison.
Implementing an interface looks like class inheritance. The syntax is the same...but it's more like a contract, since an interface has no code to inherit. If you make a class that goes like:
class MyClass: IComparable<MyClass>
{
//--> stuff
}
...then you're obligated to have a publicly visible method with the signature:
int CompareTo( MyClass a, MyClass b )
{
//--> look at the two instances and make a determination...
}
The method can use any characteristics of the class to determine what makes a greater than, less than, or equal to b...and thereby control how it's going to be placed into a structure.
A class can inherit from only one other class...but it can implement as many interfaces as it needs. This is what, I'm guessing, looks like multiple inheritance.
a. There is no real inheritance in your code. Only the implementation of a standard interface, IComparable<T>. Implementing an interface is sometimes called inheritance but it is not the same. In this case it forces Company to implement the CompareTo() method.
b. The code you have a question about just creates a temporary object. You can rewrite it to something that might be easier to understand:
//return stri.Search(new Company() { Bezeichnung = bezeichnung });
var tempCompany = new Company() { Bezeichnung = bezeichnung };
return stri.Search(tempCompany);
Related
I need to iterate through list I created, but can't access objects inside. I tried a few different functions but nothing worked and I'm afraid I'm using the wrong tools for the job.
namespace WholesaleApp
{
internal class Program : Wholesale
{
static string filePath = "C:\\Wholesale.txt";
static void Main(string[] args)
{
List<Merchandise> productList = new List<Merchandise>();
productList = ReadFromFile(filePath);
foreach(Merchandise merchandise in productList)
{
//this is where I'm trying to access objects inside and display them
}
}
}
}
This is my abstract class:
namespace WholesaleApp
{
internal abstract class Merchandise
{
public string merchandiseName { get; set; }
public int merchandiseAmount { get; set; }
public Merchandise(string name, int amount)
{
merchandiseName = name;
merchandiseAmount = amount;
}
}
}
And this is one of the three classes deriving from Merchandise abstract class:
namespace WholesaleApp
{
internal class MerchandiseClothing : Merchandise
{
public string clothSize { get; set; }
public string clothType { get; set; }
public MerchandiseClothing(string _clothType, string _clothSize, string name, int amount) : base(name, amount)
{
clothType = _clothType;
clothSize = _clothSize;
}
public void ReturnAll()
{
Console.Write(merchandiseName+" of type: "+clothSize+" in amount: "+merchandiseAmount+ " and jeep status is: "+clothType);
}
}
}
Finally, my function where I add everything to the final list:
namespace WholesaleApp
{
internal class Wholesale
{
static public List<Merchandise> ReadFromFile(string filePath)
{
List<Merchandise> result = new List<Merchandise>();
string line;
StreamReader reader = null!;
try
{
reader = new StreamReader(filePath);
line = reader.ReadLine()!;
while (line != null)
{
string[] words = line.Split(';');
if (words[0] == "MerchandiseComputer")
{
result.Add(new MerchandiseComputer(words[1], words[2], Int32.Parse(words[3])));
}
else if (words[0] == "MerchandiseCarParts")
{
result.Add(new MerchandiseCarParts(bool.Parse(words[1]), words[3], words[2], Int32.Parse(words[4])));
}
else if (words[0] == "MerchandiseClothing")
{
result.Add(new MerchandiseClothing(words[1], words[2], words[3], Int32.Parse(words[4])));
}
line = reader.ReadLine()!;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
reader.Close();
}
return result;
}
}
}
It should be possible to iterate here iterate through objects already. If you want to use specific fields from each specific class, you can put here a check on type and do whatever you want. For example:
foreach (Merchandise merchandise in productList)
{
if (merchandise is MerchandiseClothing clothing)
{
Console.WriteLine(clothing.clothSize); //Can be use any field from Clothing class
Console.WriteLine(clothing.merchandiseAmount); //And also from parent
}
else if (merchandise is MerchandiseComputer computer)
{
//Do what you want
}
}
However, better to make abstract method like WriteToConsole in Merchandise class and override it in each implementation. Like ReturnAll method in your MerchandiseClothing class
I'm trainee and have a problem with that I can't solve this problem alone. So please help me. I found many topics but I could not find a solution.
I just start to learn C# and I'm not sure how to do this. I know that is a simple job but realy I need to understand and solve it. I try to do something but it is only some code. I did my binary tree with some values, have a node class and print method.
Please tell me how to write a code that can read a tree from the Console, because I don't want to have any hardcorde. And then how to find a lowest common ancestor - I see the BFS and DFS algorithms so maybe I can find something, but I'm not sure.
I've read much about this but I can not explain many things. Her
Here is the my code:
class Program
{
static void Main(string[] args)
{
var binatyTree = new BinaryTree<int>(1,
new BinaryTree<int>(2,
new BinaryTree<int>(4),
new BinaryTree<int>(5)),
new BinaryTree<int>(3,
new BinaryTree<int>(6,
new BinaryTree<int>(9),
new BinaryTree<int>(10)),
new BinaryTree<int>(7))
);
Console.WriteLine("Binary Tree:");
binatyTree.Print();
}
}
my binary tree and print method:
public class BinaryTree<T>
{
public T Value { get; set; }
public BinaryTree<T> LeftChildren { get; set; }
public BinaryTree<T> RightChildren { get; set; }
public BinaryTree(T value, BinaryTree<T> leftChildren = null, BinaryTree<T> rightChildren = null)
{
this.Value = value;
this.LeftChildren = leftChildren;
this.RightChildren = rightChildren;
}
public void Print (int indent = 0)
{
Console.Write(new string (' ', 2*indent));
Console.WriteLine(this.Value);
if (this.LeftChildren != null)
{
this.LeftChildren.Print(indent + 1);
}
if (this.RightChildren != null)
{
this.RightChildren.Print(indent + 1);
}
}
my class Node:
class Node
{
private int data;
private Node left;
private Node right;
public Node(int data = 0)
{
this.data = 0;
left = null;
right = null;
}
}
So please I realy need to understand every connections so please if you can explain for me and help.
So here is my Binary tree code.
using System;
namespace MyBinaryTree
{
// Creates a binary tree
// Finds the lowest common ancestor in a binary tree
class МainSolution
{
static void Main(string[] args)
{
// Initialises binary tree view
var btView = new ViewBinaryTree();
btView.BinaryTreeView();
// Initialises new binary tree
BinarySearchTree tree = new BinarySearchTree();
// Reads the desired number of nodes
Console.Write("Enter how many nodes you want: ");
int number = int.Parse(Console.ReadLine());
Console.WriteLine();
// Reads the nodes' values
for (int i = 1; i <= number; i++)
{
Console.Write($"Enter name of {i} node: ");
string nodeName = Console.ReadLine().ToUpper();
tree.Insert(nodeName);
}
// Lowest common ancestor - reads the two required values
// Checks the values
// Prints the lowest common ancestor
bool isValid = true;
while (isValid)
{
Console.WriteLine();
Console.Write("Please enter the first node value: ");
string nameOne = Console.ReadLine().ToUpper();
Console.Write("Please enter the second node value: ");
string nameTwo = Console.ReadLine().ToUpper();
if (tree.Find(nameOne) == true && tree.Find(nameTwo) == true)
{
Console.WriteLine();
var result = tree.SearchLCA(tree.root, nameOne, nameTwo);
Console.WriteLine($"Lowest common ancestor: {result} ");
Console.WriteLine();
isValid = false;
}
else
{
Console.WriteLine();
Console.WriteLine("Please enter a valid name!");
}
}
}
}
}
Create a class Node:
// Creates the node structure
class Node
{
public string Data { get; set; }
public Node RightChild { get; set; }
public Node LeftChild { get; set; }
public Node(string data, Node left = null, Node right = null)
{
this.Data = data;
this.LeftChild = left;
this.RightChild = right;
}
}
Here is my logic
// Creates a binary tree.
class BinarySearchTree
{
public Node root; // Creates a root node.
public BinarySearchTree()
{
this.root = null;
}
// Adds a node in the binary tree.
public void Insert(string inputValue)
{
Node newNode = new Node(inputValue); // Creates a new node.
if (root == null) // If the tree is empty, inserts the new node as root
{
root = newNode;
return;
}
//Determins where to place the new node in the binary tree.
Node current = root;
Node parent = null;
while (true)
{
parent = current;
if (inputValue.CompareTo(current.Data) < 0)
{
current = current.LeftChild;
if (current == null)
{
parent.LeftChild = newNode;
return;
}
}
else
{
current = current.RightChild;
if (current == null)
{
parent.RightChild = newNode;
return;
}
}
}
}
// Checks if the node exists in the binary tree
public bool Find(string inputValue)
{
Node current = root;
while (current != null)
{
if (current.Data.Equals(inputValue))
{
return true;
}
else if (current.Data.CompareTo(inputValue) > 0)
{
current = current.LeftChild;
}
else
{
current = current.RightChild;
}
}
return false;
}
// Creates a method to find the lowest common ancestor(LCA).
public object SearchLCA(Node searchTree, string compareValue1, string compareValue2)
{
if (searchTree == null)
{
return null;
}
if (searchTree.Data.CompareTo(compareValue1) > 0 && searchTree.Data.CompareTo(compareValue2) > 0)
{
return SearchLCA(searchTree.LeftChild, compareValue1, compareValue2);
}
if (searchTree.Data.CompareTo(compareValue1) < 0 && searchTree.Data.CompareTo(compareValue2) < 0)
{
return SearchLCA(searchTree.RightChild, compareValue1, compareValue2);
}
return searchTree.Data;
}
}
"Thank you!"
I have created custom linked list in c#.
LinkedList.cs:
class LinkedList
{
private Node Start;//Mazgas pr
private Node End;//Mazgas pb
private Node Current;// Mazas d saraso sasajai
public LinkedList()
{
this.Start = null;
this.End = null;
this.Current = null;
}
public Object Get(int index)
{
for( Node curr = Start; curr != null; curr = curr.Next)
{
if( curr.Index == index )
return curr.Data;
}
return null;
}
public void PrintData()
{
for (Node curr = Start; curr != null; curr = curr.Next)
{
Console.WriteLine("{0}: {1}", curr.Index, curr.Data);
}
}
public int Count()
{
int i = 0;
for( Node curr = Start; curr != null; curr = curr.Next, i++);
return i;
}
public void Add(Object data)
{
Node current = new Node(data, null);
if (Start != null)
{
End.Next = current;
End.Next.Index = End.Index + 1;
End = current;
}
else
{
Start = current;
End = current;
End.Index = 0;
}
}
}
Node.cs:
class Node
{
public Object Data { get; set; }
public Node Next { get; set; }
public int Index { get; set; }
public Node() { }
public Node(Object data, Node next )
{
Data = data;
Next = next;
}
public override string ToString ()
{
return string.Format ("Data: {0}", Data);
}
}
and Part.cs
class Part
{
public string Code { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public Part(string code, string name, double price)
{
Code = code;
Name = name;
Price = price;
}
public Part() { }
public override string ToString()
{
return string.Format("{0} {1}", Name, Code);
}
}
Problem is, when i create list LinkedList parts = new LinkedList()
and add objects to it parts.Add(new Part("code", "name", 10)); i can't access Part object variables. I need to do this:
for( int i=0; i<parts.Count(); i++)
{
Console.WriteLine("{0}", (Part)Parts.Get(i).Name);
}
but it gives me error:
Error CS1061: Type 'object' does not contain a definition for 'Name'
and no extension method 'Name' of type 'object' could be found. Are
you missing an assembly reference? (CS1061)
EDITED: I need this linked list to be flexible for any type of object.
(Part)Parts.Get(i).Name is equivalent to (Part)(Parts.Get(i).Name) and since return value of your Get(i) is of type object and object doesn't have Name property, you received the exception.
You can correct it this way:
((Part)Parts.Get(i)).Name
Note:
I suppose it's just for learning purpose.
If all items of the list are of the same type, you can make your Generic classes. Having a generic Node<T> and LinkedList<T> class you can change the input parameters and return values to T instead of object.
In a real application, you can use LinkedList<T> or other generic data structures available.
I'm trying to dynamically combin lambda expressions. The code below will explain what I want. This is NOT a case of combining a=>b and b=>c to a=>c. Instead, I want to prevent code duplication by reusing conversion-expressions:
class User // convert from...
{
public string FirstName {get;set;}
public string LastName {get;set;}
}
class Person // convert to...
{
public string Name
}
public class UserTransaction
{
User FromUser {get;set;}
User ToUser {get;set;}
decimal Amount {get;set;}
}
public class PersonTransaction
{
Person FromPerson {get;set;}
Person ToPerson {get;set;}
bool IsPositive;
}
Expression<Func<User, Person>> ToPerson = u => new Person {Name = u.FirstName + " " + u.LastName};
Expression<Func<UserTransaction, PersonTransaction>> PersonTransaction = ut => new PersonTransaction {
FromPerson = FromUser.Compile()(ut.FromUser), // Actually, I do not want to compile
ToPerson = ToUser.Compile()(ut.FromUser), // (or double code)
IsPositive = ut.Amount > 0
}
In the example above, I already have an expression to convert a user to a person. I do not want to duplicate this code or compile it. I've tried using stripping out the "compile"-calls by manually editing the expression tree. I did not succeed. Has anybody tried something similar and succeed?
You can do some voodoo with ExpressionVisitor to rewrite your existing code to be fully inline; this:
detects the invoke
locates the Compile
resolves the originating lambda
swaps in all the parameter values directly
rebuilds the expression tree accordingly
Have fun!
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;
public class User // convert from...
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Person // convert to...
{
public string Name { get; set; }
}
public class UserTransaction
{
public User FromUser { get; set; }
public User ToUser { get; set; }
public decimal Amount { get; set; }
}
public class PersonTransaction
{
public Person FromPerson { get; set; }
public Person ToPerson { get; set; }
public bool IsPositive { get; set; }
}
static class Program
{
static void Main()
{
Expression<Func<User, Person>> ToPerson = u => new Person { Name = u.FirstName + " " + u.LastName };
Expression<Func<UserTransaction, PersonTransaction>> PersonTransaction = ut => new PersonTransaction
{
FromPerson = ToPerson.Compile()(ut.FromUser), // Actually, I do not want to compile
ToPerson = ToPerson.Compile()(ut.ToUser), // (or double code)
IsPositive = ut.Amount > 0
};
var visitor = new RemoveCompilationsExpressionVisitor();
var inlined = (Expression<Func<UserTransaction, PersonTransaction>>)visitor.Visit(PersonTransaction);
}
class ParameterSwapExpressionVisitor :ExpressionVisitor
{
private readonly Dictionary<ParameterExpression, Expression> swaps;
public ParameterSwapExpressionVisitor(Dictionary<ParameterExpression, Expression> swaps)
{
this.swaps = swaps;
}
protected override Expression VisitParameter(ParameterExpression node)
{
Expression result;
return swaps.TryGetValue(node, out result) ? result : base.VisitParameter(node);
}
}
class RemoveCompilationsExpressionVisitor : ExpressionVisitor
{
protected override Expression VisitInvocation(InvocationExpression node)
{
var lambda = TryGetInnerLambda(node.Expression);
if(lambda != null)
{
// this would be a partial solution, but we want to go further!
// return Expression.Invoke(lambda, node.Arguments);
var swaps = new Dictionary<ParameterExpression, Expression>();
for(int i = 0; i < lambda.Parameters.Count; i++)
{
swaps.Add(lambda.Parameters[i], node.Arguments[i]);
}
var visitor = new ParameterSwapExpressionVisitor(swaps);
return visitor.Visit(lambda.Body);
}
return base.VisitInvocation(node);
}
LambdaExpression TryGetInnerLambda(Expression node)
{
try
{
if(node.NodeType == ExpressionType.Call)
{
var mce = (MethodCallExpression)node;
var method = mce.Method;
if (method.Name == "Compile" && method.DeclaringType.IsGenericType && method.DeclaringType.GetGenericTypeDefinition()
== typeof(Expression<>))
{
object target;
if (TryGetLiteral(mce.Object, out target))
{
return (LambdaExpression)target;
}
}
}
}
catch (Exception ex)
{
/* best effort only */
Debug.WriteLine(ex);
}
return null;
}
static bool TryGetLiteral(Expression node, out object value)
{
value = null;
if (node == null) return false;
switch(node.NodeType)
{
case ExpressionType.Constant:
value = ((ConstantExpression)node).Value;
return true;
case ExpressionType.MemberAccess:
var me = (MemberExpression)node;
object target;
if (TryGetLiteral(me.Expression, out target))
{
switch (me.Member.MemberType)
{
case System.Reflection.MemberTypes.Field:
value = ((FieldInfo)me.Member).GetValue(target);
return true;
case MemberTypes.Property:
value = ((PropertyInfo)me.Member).GetValue(target, null);
return true;
}
}
break;
}
return false;
}
}
}
Let´s say I have two classes:
public Foo
{
public List<Foo> Childs { get; set; }
public Bar BarObj { get; set; }
public int Level { get; set; }
}
public Bar
{
public List<Foo> Childs { get; set; }
}
Now I want to get the nesting-level from a Collection of "Foo" Objects
my current working Method looks like this:
int currentLevel = 0;
public void ApplyNestingLevel(List<Foo> list)
{
foreach(var item in list)
{
item.Level = currentLevel;
if(item.Childs.Count > 0 || item.BarObj.Childs.Count > 0)
{
currentLevel++;
}
ApplyNestingLevel(item.Childs);
ApplyNestingLevel(item.BarObj.Childs);
}
}
how could I make this more "elegant/simple" ?
public void ApplyNestingLevel(Foo f)
{
ApplyNestingLevel(f, 0);
}
public void ApplyNestingLevel(Foo f, int level)
{
if(f == null) { return; }
f.Level = level
if(f.Childs != null) {
foreach(Foo child in f.Childs)
{
ApplyNestingLevel(child, level + 1);
}
}
if(f.BarObj != null && f.BarObj.Childs != null) {
foreach(Foo child in f.BarObj.Childs)
{
ApplyNestingLevel(child, level + 1);
}
}
}
Store a reference to the parent and make the Level property recursive.
I added an example and a couple other design suggestions in the code sample below. Hope this helps. FYI, this is pretty much straight out of the Gang of Four's design for the Composite Pattern, which should be required reading for anyone who is serious about OOP.
DoFactory .NET Composite Pattern
Design Patterns: Elements of Reusable Object-Oriented Software, on Amazon.com
public class Foo
{
public Foo(Foo parent = default(Foo))
{
this.parent = parent;
this.children = new List<Foo>();
}
private readonly Foo parent;
private readonly List<Foo> children;
public int Level { get { return ReferenceEquals(parent,null) ? 0 : parent.Level + 1; } }
// don't expose the actual list... see below for why
public IEnumerable<Foo> Children { get { foreach(Foo child in this.children) yield return child; } }
// instead of exposing the child object list
// declare an explicit method with any parameters
// necessary. this allows you to enforce the invariant
// condition that all objects in a children collection
// will have their parent reference set to their
// actual parent
public void AddChild()
{
Foo newChild = new Foo(parent:this);
this.children.Add(newChild);
}
// if you need the ability to remove items as well,
// you can expose a remove method too. Just make
// sure that you validate expected preconditions
public int RemoveChild(Foo childToRemove)
{
if(ReferenceEquals(childToRemove,null)) throw new ArgumentNullException("childToRemove");
if(!ReferenceEquals(this,childToRemove.parent)) throw new ArgumentException("The object cannot be removed because the current object is not the correct parent.","childToRemove");
return children.RemoveAll((Foo existentChild) => existentChild.Equals(childToRemove));
}
}
my version, i using extensions.
public static class EnumerableExtensions
{
/// <summary>Get max nesting level.</summary>
/// <param name="source">Source.</param>
/// <param name="children">Selector.</param>
/// <typeparam name="T">Type.</typeparam>
/// <returns><see cref="IEnumerable{T}"/>.</returns>
public static int GetMaxNestingLevel<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> children)
{
return source.SelectMany(x => GetNestingLevel(x, 0)).Max();
IEnumerable<int> GetNestingLevel(T source, int level)
{
if (children(source) != null)
{
return children(source).SelectMany(x => GetNestingLevel(x, level + 1));
}
else
{
return new List<int> { level }
}
}
}
}
than u can use it like
var max = Foo.Childs.GetMaxNestingLevel(x => x.Childs);
ps
mayby you net tests (NUnit)
using NUnit.Framework;
....
public class EnumerableExtensionsTests
{
private static IEnumerable GetMaxNestingLevelTestCases
{
get
{
yield return new TestCaseData(new int[] { 1, 2, 3, 4 }).Returns(4);
yield return new TestCaseData(new int[] { 4, 3, 2, 1 }).Returns(4);
yield return new TestCaseData(new int[] { 1, 10, 0, 1 }).Returns(10);
yield return new TestCaseData(new int[] { 1, 1, 1, 1 }).Returns(1);
yield return new TestCaseData(new int[] { 1, 1, 1, 2 }).Returns(2);
}
}
[TestCaseSource(nameof(GetMaxNestingLevelTestCases))]
public int GetMaxNestingLevelTest(ICollection<int> sourceNestingLevel)
{
var testSource = sourceNestingLevel.Select(x => new NestingLevelTestClass(x)).ToList();
return testSource.GetMaxNestingLevel(x => x.Children);
}
private class NestingLevelTestClass
{
public NestingLevelTestClass(int childrenLevel = 0)
{
if (childrenLevel != 0)
{
Children = new List<NestingLevelTestClass>
{
new NestingLevelTestClass(childrenLevel - 1),
};
}
}
public ICollection<NestingLevelTestClass> Children { get; set; }
}
}