Populate a TreeView from an object - c#

I am having a problem with a treeview in my WinForm app. I created a TreeViewItem class that holds the data. There are only 5 fields: CaseNoteID, ContactDate, ParentNoteID, InsertUser, ContactDetails.
public class TreeItem
{
public Guid CaseNoteID;
public Guid? ParentNoteID;
public string ContactDate;
public string InsertUser;
public string ContactDetails;
public TreeItem(Guid caseNoteID, Guid? parentNoteID, string contactDate, string contactDetails, string insertUser)
{
CaseNoteID = caseNoteID;
ParentNoteID = parentNoteID;
ContactDate = contactDate;
ContactDetails = contactDetails;
InsertUser = insertUser;
}
}
The plan was to show relationships of the notes by showing a note under it's parent as determined by the ParentNoteID field. Pretty simplistic really. Unfortunately, all my attempts so far have put a "child" note, one with a ParentNoteID, in both positions. The first level AND under it's appropriate Parent.
When I step through my code my data is coming back accurately.
List<TreeItem> items = BLLMatrix.GetTreeViewData(HUD.PersonId);
PopulateTree(tvwCaseNotes,items);
I just don't know how to take that and populate my TreeView accurately with it. This is what I started but now I am stuck.
public static void PopulateTree(TreeView tree, ICollection<TreeItem> items)
I just don't seem able to wrap my head around it. Do I need to split my data call up and first return all entrys with ParentNoteID = null and then go get the rest and somehow join the two?
#Hogan: I apologize for the drastic change in the question. It was evident from your response that I hadn't approached this from a good angle in the first place. In the second place, the original method still did not work.

Maybe i completely misunderstood you, but you have a flat hierarchy where each element knows its parent. Now you have to create each element and afterwards built up the hierarchy. Here is a first quick shot of such an implementation (missing cyclic checks, error handling, etc.):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
PopulateTreeView(treeView, SampleData());
}
private IEnumerable<Item> SampleData()
{
yield return new Item { CaseID = "1" };
yield return new Item { CaseID = "2" };
yield return new Item { CaseID = "3" };
yield return new Item { CaseID = "4", ParentID = "5" };
yield return new Item { CaseID = "5", ParentID = "3" };
yield return new Item { CaseID = "6" };
yield return new Item { CaseID = "7", ParentID = "1" };
yield return new Item { CaseID = "8", ParentID = "1" };
}
private void PopulateTreeView(TreeView tree, IEnumerable<Item> items)
{
Dictionary<string, Tuple<Item, TreeNode>> allNodes = new Dictionary<string, Tuple<Item, TreeNode>>();
foreach (var item in items)
{
var node = CreateTreeNode(item);
allNodes.Add(item.CaseID, Tuple.New(item, node));
}
foreach (var kvp in allNodes)
{
if (kvp.Value.First.ParentID != null)
{
allNodes[kvp.Value.First.ParentID].Second.Nodes.Add(kvp.Value.Second);
}
else
{
tree.Nodes.Add(kvp.Value.Second);
}
}
}
private TreeNode CreateTreeNode(Item item)
{
var node = new TreeNode();
node.Text = item.CaseID;
return node;
}
}
public class Item
{
public string CaseID { get; set; }
public string ParentID { get; set; }
}
public class Tuple<T>
{
public Tuple(T first)
{
First = first;
}
public T First { get; set; }
}
public class Tuple<T, T2> : Tuple<T>
{
public Tuple(T first, T2 second)
: base(first)
{
Second = second;
}
public T2 Second { get; set; }
}
public static class Tuple
{
//Allows Tuple.New(1, "2") instead of new Tuple<int, string>(1, "2")
public static Tuple<T1> New<T1>(T1 t1)
{
return new Tuple<T1>(t1);
}
public static Tuple<T1, T2> New<T1, T2>(T1 t1, T2 t2)
{
return new Tuple<T1, T2>(t1, t2);
}
}
What is a Tuple?
Just to answer the question in the comment:
Take a look at Wikipedia.
Take a look at this StackOverflow question.
It is a simple container object holding two other objects. That's it.
I used it, cause in my Dictionary is a unqiue identifier (string CaseID) which references on two objects (TreeNode and Item). Another approach would be to make two Dictionaries as Dictionary<string, TreeNode> and Dictionary<string, Item>, but because there is a 1:1 relationship i took the tuple approach.
Maybe rename it to ItemTreeNodeContainer and it will get more clearer for you what it means in the concrete situation.

The basic idea of recursion is you use the stack as a temporary store for variables on each call. However, you are referencing a global variable in your recursive call. When you change it (via the filter function) it will invalidate all prior calls in the recursion. You need to remove the recursion or push a new copy (and not a reference like you are doing) of the control variable (the rows) on the stack.
edit based on comment
I hate putting code out there without being able to test it, but I believe something like this should work to solved the problem I described.
Here is the problem area:
// using the Find method uses a Predicate generic delegate.
if (nodeList.Find(FindNode) == null)
{
var tmpCNoteID = dr["CaseNoteID"].ToString();
var filter = "ParentNote='" + tmpCNoteID + "'";
DataRow[] childRows = cNoteDT.Select(filter);
if (childRows.Length > 0)
{
// Recursively call this function for all childRows
TreeNode[] childNodes = RecurseRows(childRows);
// Add all childnodes to this node
node.Nodes.AddRange(childNodes);
}
// Mark this noteID as dirty (already added)
nodeList.Add(node);
}
Something like this should fix the problem I see (note: this is not elegant or good code, it is just a fix to the problem I describe above, I would never put my name to this code). Also, without being able to test the code I can't even be sure this is the problem.
// using the Find method uses a Predicate generic delegate.
if (nodeList.Find(FindNode) == null)
{
var tmpCNoteID = dr["CaseNoteID"].ToString();
var filter = "ParentNote='" + tmpCNoteID + "'";
DataTable DTCopy = cNoteDT.Copy()
DataRow[] childRows = DTCopy.Select(filter);
if (childRows.Length > 0)
{
// Recursively call this function for all childRows
TreeNode[] childNodes = RecurseRows(childRows);
// Add all childnodes to this node
node.Nodes.AddRange(childNodes);
}
// Mark this noteID as dirty (already added)
nodeList.Add(node);
}

Solved my problem using Oliver's solution. Just refactored it using Tuple that part of .Net 4.0
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
PopulateTreeView(treeView1, SampleData());
}
private IEnumerable<Item> SampleData()
{
yield return new Item { CaseID = "1" };
yield return new Item { CaseID = "2" };
yield return new Item { CaseID = "3" };
yield return new Item { CaseID = "4", ParentID = "5" };
yield return new Item { CaseID = "5", ParentID = "3" };
yield return new Item { CaseID = "6" };
yield return new Item { CaseID = "7", ParentID = "1" };
yield return new Item { CaseID = "8", ParentID = "1" };
}
private void PopulateTreeView(TreeView tree, IEnumerable<Item> items)
{
Dictionary<string, Tuple<Item, TreeNode>> allNodes = new Dictionary<string, Tuple<Item, TreeNode>>();
foreach (var item in items)
{
var node = CreateTreeNode(item);
allNodes.Add(item.CaseID, Tuple.Create(item, node));
}
foreach (var kvp in allNodes)
{
if (kvp.Value.Item1.ParentID != null)
{
allNodes[kvp.Value.Item1.ParentID].Item2.Nodes.Add(kvp.Value.Item2);
}
else
{
tree.Nodes.Add(kvp.Value.Item2);
}
}
}
private TreeNode CreateTreeNode(Item item)
{
var node = new TreeNode();
node.Text = item.CaseID;
return node;
}
}
public class Item
{
public string CaseID { get; set; }
public string ParentID { get; set; }
}
Tuple Help on MSDN:
Tuple Class
In my case I'm passing data source from entity framework: Entities.Categories
and replaced Item class with Category class generated by entity framework.

Related

Recursion returns a list, not of its own elements, but of others

I have documents that are based on others, through recursion, I find documents that refer to what they are based on, the problem is that they are all duplicated into one, it does not work correctly
not the correct variant
I want to get this
In the code, the main thing that I transfer is the Type of the document and the List of child elements
public async Task<List<DocumentTreeItem>> FillRecursionTree(Guid documentId, string documentPresentationName, List<DocumentTreeItem> treeItems, Type documentType)
{
await FillRecursionTree(documentId, documentPresentationName, treeItems, documentType);
return treeItems;
async Task FillRecursionTree(Guid childrenId, string childrenIdDocumentPresentationName, List<DocumentTreeItem> childrenIdTreeItems, Type childrenIdDocumentType)
{
var currentNode = new DocumentTreeItem(documentPresentationName, childrenIdDocumentType, childrenIdTreeItems)
{
Id = childrenId,
DocumentPresentationName = childrenIdDocumentPresentationName,
TypeDocument = childrenIdDocumentType
};
childrenIdTreeItems.Add(currentNode);
var customerInvoices = await GetBaseCustomerInvoiceDocuments(childrenId);
foreach (var customerInvoice in customerInvoices)
{
childrenIdDocumentType = customerInvoice.GetType();
await FillRecursionTree(customerInvoice.Id, customerInvoice.DocumentPresentationName, **currentNode.Childrens,** childrenIdDocumentType);
}
}
}
if i think correctly i need to add elements to the root element but how do i do it so i don't get then all the elements again if they don't fit
currentNode.Childrens <-
How can I pass from the main document only the required array of child elements, and not all at once, where everything falls.
Maybe I'm wrong and the problem is in the second one.
This is the type in which I keep everything, there is a children's letter in which all the documents made on its basis are recorded.
public Guid Id { get; set; }
public string? DocumentPresentationName { get; set; }
public Type TypeDocument { get; set; }
public List<DocumentTreeItem> Childrens { get; set; } = new List<DocumentTreeItem>();
public DocumentTreeItem(string documentPresentationName, Type typeDocument, List<DocumentTreeItem> children = null)
{
DocumentPresentationName = documentPresentationName;
TypeDocument = typeDocument;
if (children != null)
Children.AddRange(children);
}
public List<DocumentTreeItem> Children
{
get
{
return Childrens;
}
}
I passed the entire array of elements of the root, and did not create a new one
var currentNode = new DocumentTreeItem(documentPresentationName, childrenIdDocumentType, **new List<DocumentTreeItem>()**)
{
Id = childrenId,
DocumentPresentationName = childrenIdDocumentPresentationName,
TypeDocument = childrenIdDocumentType
};

How to read large text files and keep tracking of the information of previous lines using C#?

(This problem is a adaptation of a real life scenario, I reduced the problem so it is easy to understand, otherwise this question would be 10000 lines long)
I have a pipe delimited text file that looks like this (the header is not in the file):
Id|TotalAmount|Reference
1|10000
2|50000
3|5000|1
4|5000|1
5|10000|2
6|10000|2
7|500|9
8|500|9
9|1000
The reference is optional and is the Id of another entry in this text file. The entries that have a reference, are considered "children" of that reference, and the reference is their parent. I need to validate each parent in the file, and the validation is that the sum of TotalAmount of it's children should be equal to the parent's total amount. The parents can be either first or before their children in the file, like the entry with Id 9, that comes after it's children
In the provided file, the entry with Id 1 is valid, because the sum of the total amount of it's children (Ids 3 and 4) is 10000 and the entry with Id 2 is invalid, because the sum of it's children (Ids 5 and 6) is 20000.
For a small file like this, I could just parse everything to objects like this (pseudo code, I don't have a way to run it now):
class Entry
{
public int Id { get; set; }
public int TotalAmout { get; set; }
public int Reference { get; set; }
}
class Validator
{
public void Validate()
{
List<Entry> entries = GetEntriesFromFile(#"C:\entries.txt");
foreach (var entry in entries)
{
var children = entries.Where(e => e.Reference == entry.Id).ToList();
if (children.Count > 0)
{
var sum = children.Sum(e => e.TotalAmout);
if (sum == entry.TotalAmout)
{
Console.WriteLine("Entry with Id {0} is valid", entry.Id);
}
else
{
Console.WriteLine("Entry with Id {0} is INVALID", entry.Id);
}
}
else
{
Console.WriteLine("Entry with Id {0} is valid", entry.Id);
}
}
}
public List<Entry> GetEntriesFromFile(string file)
{
var entries = new List<Entry>();
using (var r = new StreamReader(file))
{
while (!r.EndOfStream)
{
var line = r.ReadLine();
var splited = line.Split('|');
var entry = new Entry();
entry.Id = int.Parse(splited[0]);
entry.TotalAmout = int.Parse(splited[1]);
if (splited.Length == 3)
{
entry.Reference = int.Parse(splited[2]);
}
entries.Add(entry);
}
}
return entries;
}
}
The problem is that I am dealing with large files (10 GB), and that would load way to many objects in memory.
Performance itself is NOT a concern here. I know that I could use dictionaries instead of the Where() method for example. My only problem now is performing the validation without loading everything to memory, and I don't have any idea how to do it, because a entry at the bottom of the file may have a reference to the entry at the top, so I need to keep track of everything.
So my question is: it is possible to keep track of each line in a text file without loading it's information into memory?
Since performance is not an issue here, I would approach this in the following way:
First, I would sort the file so all the parents go right before their children. There are classical methods for sorting huge external data, see https://en.wikipedia.org/wiki/External_sorting
After that, the task becomes pretty trivial: read a parent data, remember it, read and sum children data one by one, compare, repeat.
All you really need to keep in memory is the expected total for each non-child entity, and the running sum of the child totals for each parent entity. Everything else you can throw out, and if you use the File.ReadLines API, you can stream over the file and 'forget' each line once you've processed it. Since the lines are read on demand, you don't have to keep the entire file in memory.
public class Entry
{
public int Id { get; set; }
public int TotalAmount { get; set; }
public int? Reference { get; set; }
}
public static class EntryValidator
{
public static void Validate(string file)
{
var entries = GetEntriesFromFile(file);
var childAmounts = new Dictionary<int, int>();
var nonChildAmounts = new Dictionary<int, int>();
foreach (var e in entries)
{
if (e.Reference is int p)
childAmounts.AddOrUpdate(p, e.TotalAmount, (_, n) => n + e.TotalAmount);
else
nonChildAmounts[e.Id] = e.TotalAmount;
}
foreach (var id in nonChildAmounts.Keys)
{
var expectedTotal = nonChildAmounts[id];
if (childAmounts.TryGetValue(id, out var childTotal) &&
childTotal != expectedTotal)
{
Console.WriteLine($"Entry with Id {id} is INVALID");
}
else
{
Console.WriteLine($"Entry with Id {id} is valid");
}
}
}
private static IEnumerable<Entry> GetEntriesFromFile(string file)
{
foreach (var line in File.ReadLines(file))
yield return GetEntryFromLine(line);
}
private static Entry GetEntryFromLine(string line)
{
var parts = line.Split('|');
var entry = new Entry
{
Id = int.Parse(parts[0]),
TotalAmount = int.Parse(parts[1])
};
if (parts.Length == 3)
entry.Reference = int.Parse(parts[2]);
return entry;
}
}
This uses a nifty extension method for IDictionary<K, V>:
public static class DictionaryExtensions
{
public static TValue AddOrUpdate<TKey, TValue>(
this IDictionary<TKey, TValue> dictionary,
TKey key,
TValue addValue,
Func<TKey, TValue, TValue> updateCallback)
{
if (dictionary == null)
throw new ArgumentNullException(nameof(dictionary));
if (updateCallback == null)
throw new ArgumentNullException(nameof(updateCallback));
if (dictionary.TryGetValue(key, out var value))
value = updateCallback(key, value);
else
value = addValue;
dictionary[key] = value;
return value;
}
}

ObjectListView - TreeListView expand different lists in tree structure

I try to expand multiple lists in my tree structure.
Let's say I have the following classes. I have the class Product, which contains a list with its children. This is my actual tree structure.
class Product
{
int prodID;
string prodName;
List<Product> prodChildren;
List<Article> articleList;
//maybe further list...
public int ProdID
{
get { return prodID;}
set{prodID = value;}
}
public string ProdName
{
get { return prodName;}
set {prodName = value;}
}
public Product(int id, string name)
{
ProdID = id;
ProdName = name;
prodChildren = new List<Product>();
articleList = new List<Article>();
}
//...
//addProdChildren
//...
//addArticles
}
class SalesArticle
{
int articleNumber;
string articleName;
public int ArticleNumber
{
get
{
return articleNumber;
}
set
{
articleNumber = value;
}
}
public string ArticleName
{
get
{
return articleName;
}
set
{
articleName = value;
}
}
public SalesArticle(int no, string name)
{
ArticleNumber = no;
ArticleName = name;
}
}
This part works great so far, but how can I expand the articles list in the same tree? I can't get this part working.
Should look something like:
[product1]
---------[product2]
---------[product3]
--------------[article1]
--------------[article2]
--------------[article3]
--------------[article4]
---------[product4]
--------------[product5]
----------------------[articleX]
----------------------[articleX]
----------------------[articleX]
----------------------[articleX]
My CanExpandGetter and ChildrenGetter are very basic currently
tlvProduktStruktur.CanExpandGetter = delegate (object x) { return (x is Product); };
tlvProduktStruktur.ChildrenGetter = delegate (object x)
{
if (((Product)x).ProduktChildren.Count > 0)
return ((Product)x).prodChildren;
else
return null;
};
Update
---------------------------------------
I found a solution if anyone is interested:
My product class has a list of objects:
class Product
{
int prodID;
string prodName;
List<object> childItems;
...
}
Now I can add every type of objects or other lists to this object-list, for example:
Product rootProduct = new Product(1, "root");
Article artikel1 = new Article();
Article artikel2 = new Article();
//this root product has a working process which contains a list of articles
WorkingProcess wp = new WorkingProcess();
wp.add(artikel1);
wp.add(artikel2);
childItems.Add(wp);
//let's assume the root product has also two children
Product p1 = new Product(2, "sub product 1");
Product p2 = new Product(3, "sub product 2");
rootProduct.childItems.Add(p1);
rootProduct.childItems.Add(p2);
The structure looks like the following:
rootProduct
------WorkingProcess
-----------Article1
-----------Article2
------SubProduct1
------SubProduct2
Now we only need to change the CanExpandGetter and ChildrenGetter:
// when the node can be expanded
tlvProduktStruktur.CanExpandGetter = delegate (object x) {
//if the product has child items (working process and/or child products) show it as expandable
if (x is Product)
if (((Product)x).ChildItems.Count > 0)
return true;
//if the working process has articles, show it as expandable
if (x is WorkingProcess)
if (((WorkingProcess)x).ArticleList.Count > 0)
return true;
return false;
};
tlvProduktStruktur.ChildrenGetter = delegate (object x) {
//check the type and expand its children
//show the child items (working process and/or child products) of the current product
if (x is Product)
if (((Product)x).ChildItems.Count > 0)
{
return ((Product)x).ChildItems;
}
//show the articles of the working process
if (x is WorkingProcess)
if (((WorkingProcess)x).ArticleList.Count > 0)
return ((WorkingProcess)x).ArticleList;
return new List<object>();
};
Now you should get the expected result.

Creating a List of Lists in C#

I seem to be having some trouble wrapping my head around the idea of a Generic List of Generic Lists in C#. I think the problem stems form the use of the <T> argument, which I have no prior experience playing with. Could someone provide a short example of declaring a class which is a List, that therein contains another List, but where the type of the object contained therein is not immediately known?
I've been reading through the MS documentation on Generics, and I am not immediately sure if I can declare a List<List<T>>, nor how exactly to pass the <T> parameter to the inside list.
Edit: Adding information
Would declaring a List<List<T>> be considered legal here? In case you are wondering, I am building a class that allows me to use a ulong as the indexer, and (hopefully) steps around the nasty 2GB limit of .Net by maintaining a List of Lists.
public class DynamicList64<T>
{
private List<List<T>> data = new List<List<T>>();
private ulong capacity = 0;
private const int maxnumberOfItemsPerList = Int32.MaxValue;
public DynamicList64()
{
data = new List<List<T>>();
}
A quick example:
List<List<string>> myList = new List<List<string>>();
myList.Add(new List<string> { "a", "b" });
myList.Add(new List<string> { "c", "d", "e" });
myList.Add(new List<string> { "qwerty", "asdf", "zxcv" });
myList.Add(new List<string> { "a", "b" });
// To iterate over it.
foreach (List<string> subList in myList)
{
foreach (string item in subList)
{
Console.WriteLine(item);
}
}
Is that what you were looking for? Or are you trying to create a new class that extends List<T> that has a member that is a `List'?
or this example, just to make it more visible:
public class CustomerListList : List<CustomerList> { }
public class CustomerList : List<Customer> { }
public class Customer
{
public int ID { get; set; }
public string SomethingWithText { get; set; }
}
and you can keep it going. to the infinity and beyond !
A list of lists would essentially represent a tree structure, where each branch would constitute the same type as its parent, and its leaf nodes would represent values.
Implementation
public sealed class TreeList<T> : List<TreeList<T>>
{
public List<T> Values { get; } = new List<T>();
public TreeList<T> this[int index]
{
get
{
while (index > Count - 1)
{
Branch();
}
return base[index];
}
}
public TreeList<T> Branch()
{
TreeList<T> result = new TreeList<T>();
Add(result);
return result;
}
}
Example
internal static class Program
{
public static void Main()
{
// Create the root element...
TreeList<string> treeList = new TreeList<string>();
// You can add branches the old-fashioned way...
treeList.Add(new TreeList<string>());
// Add leaf node values to your first branch...
treeList[0].Values.Add("Hello, World!");
treeList[0].Values.Add("Goodbye, World!");
// You can create new branches from any branch like this...
// Note: You could also chain branch statements; i.e. treeList.Branch().Branch().Branch()
TreeList<string> branch2 = treeList.Branch();
// Add leaf node values to your second branch...
branch2.Values.Add("Alice");
branch2.Values.Add("Bob");
// You can also create branches until you reach the desired branch index...
// The TreeList indexer will loop until the desired index has been created, and then return it.
treeList[7].Values.Add("Alpha");
treeList[7].Values.Add("Bravo");
treeList[7].Values.Add("Charlie");
// How many branches does the root have?
Console.WriteLine($"Treelist branches: {treeList.Count}");
// What's at branch 0's values?
foreach (string value in treeList[0].Values)
{
Console.WriteLine(value);
}
// What's at branch 1's values?
foreach (string value in treeList[1].Values)
{
Console.WriteLine(value);
}
// What's at branch 7's values?
foreach (string value in treeList[7].Values)
{
Console.WriteLine(value);
}
}
}
Now, whether you should implement something like this is another matter. Extending List<T> isn't recommended: Why not inherit from List<T>?
public class ListOfLists<T> : List<List<T>>
{
}
var myList = new ListOfLists<string>();
I have the following code
public class ChildClass
{
public string FieldName { get; set; }
public string Value { get; set; }
public string StatusClass { get; set; }
public string StatusMessage { get; set; }
}
Creating a list of list obj is as follows
List<List<ChildClass>> obj = new List<List<ChildClass>>();
Look a direct example here:
public partial class Form1 : Form
{
List<List<Label>> txtList;
List<List<int>> num;
public Form1()
{
InitializeComponent();
txtList = new List< List<Label> >() {
new List<Label> { label1, label2, label3 },
new List<Label> { label4, label5, label6 },
new List<Label> { label7, label8, label9 }
};
num = new List<List<int>>() { new List<int>() { 1, 2 }, new List<int>() { 3, 4 } };
}
}
you should not use Nested List in List.
List<List<T>>
is not legal, even if T were a defined type.
https://msdn.microsoft.com/en-us/library/ms182144.aspx

Why IEnumerable<T> becomes empty after adding elements to a collection?

I have an IEnumerable<T> when I iterate through it and add it's element to a list it becomes empty?
Is there generally anything wrong about what I expect from the code?
public class Apple
{
private ICollection<Fruit> _fruits = new List<Fruit>();
public void AddFruits(IEnumerable<Fruit> fruits)
{
if (fruits == null) throw new ArgumentNullException("fruits");
foreach (var fruit in fruits)
{
_fruits.Add(fruit);
}
}
}
The caller code:
public void AddFruits(IEnumerable<Fruit> fruitsToAdd)
{
foreach (var apple in apples)
{
// Here fruitsToAdd has elements, fruitsToAdd.ToList() has two fruits.
apple.AddFruits(fruitsToAdd);
// Here fruitsToAdd has NO element!!, fruitsToAdd.ToList() is empty!
// next iteration will not add any fruit to next apple since fruitsToAdd is empty.
}
}
Update
The ToList() solved the problem. The root of the problem was that the caller to AddFruits(IEnumerable fruitsToAdd) send fruitsToAdd that was like.
fruitsToAdd = obj.Fruits.Except(apples.Fruits);
Each time IEnumerable fruitsToAdd was Rest it run above statement. Which at next iteration run Except and thereby returned no fruits.
The right way is fruitsToAdd = obj.Fruits.Except(apples.Fruits).ToList(); Since we want one evaluation.
Ok, try this:
public void AddFruits(IEnumerable<Fruit> fruitsToAdd)
{
var fruitsToAddCopy = fruitsToAdd.ToList(); // add just this line
foreach (var apple in apples)
{
apple.AddFruits(fruitsToAddCopy); // and change this
}
}
Without knowing the origin of your fruitsToAdd it's impossible to say more. Some IEnumerable<> can't be re-used. Others can.
I modified your code to get it to compile and wrote a test. Your list does not become empty after copying it's elements into the apples.
using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ClassLibrary3
{
[TestClass]
public class Class1
{
[TestMethod]
public void test()
{
var fruits = new List<Fruit> {new Fruit(), new Fruit(), new Fruit()};
var lists = AddFruits(fruits);
Assert.IsTrue(fruits.Count == 3);
}
public List<Apple> AddFruits(IEnumerable<Fruit> fruitsToAdd)
{
var apples = new List<Apple>
{
new Apple(),
new Apple()
};
foreach (var apple in apples)
{
apple.AddFruits(fruitsToAdd);
}
return apples;
}
}
public class Fruit
{
}
public class Apple
{
private ICollection<Fruit> _fruits = new List<Fruit>();
public void AddFruits(IEnumerable<Fruit> fruits)
{
if (fruits == null) throw new ArgumentNullException("fruits");
foreach (var fruit in fruits)
{
_fruits.Add(fruit);
}
}
}
}
The code in your question shouldn't exhibit such behavior, so I am presuming you tried to simplify it, but removed a lot of functionality from it.
What looks a bit suspicious is that your _fruits field is of type ICollection<T>. This interface is often used with custom collection implementations. Is it possible that, in the actual code, this field isn't instantiated with a List<T>, but rather with a custom implementation of that interface?
If you have a custom collection implementation, then it is perfectly possible for its Add method to do weird stuff (like removing an item from its previous "parent" collection before adding it to its new "parent"). Tree collections often do such things to simplify moving nodes around.
[Edit]
I am aware that this is not OPs actual problem, but I will nevertheless add an example to demonstrate that a custom collection implementation can in fact modify the input collection when its members are added to a different collection.
Let's say the Fruit class looks like this:
partial class Fruit
{
private ICollection<Fruit> _children;
private Fruit _parent;
public String Name { get; set; }
public Fruit()
{
_children = new FruitCollection(this);
}
public void AddFruits(IEnumerable<Fruit> fruits)
{
foreach (Fruit f in fruits)
_children.Add(f);
}
public int NumberOfChildren
{
get { return _children.Count; }
}
public IEnumerable<Fruit> GetFruits()
{
return _children.ToList();
}
}
And there is a custom collection defined as:
partial class Fruit
{
public class FruitCollection : Collection<Fruit>
{
private readonly Fruit _parent;
public FruitCollection(Fruit parent)
{
_parent = parent;
}
protected override void InsertItem(int index, Fruit item)
{
// item already has a parent?
if (item._parent != null)
{
// remove it from previous parent
item._parent._children.Remove(item);
}
// set the new parent
item._parent = _parent;
base.InsertItem(index, item);
}
// other methods should be overriden in a similar way
}
}
Then the following program:
static void Main(string[] args)
{
List<Fruit> abc = new List<Fruit>()
{
new Fruit() { Name = "a" },
new Fruit() { Name = "b" },
new Fruit() { Name = "c" }
};
Fruit apple = new Fruit() { Name = "apple" };
apple.AddFruits(abc);
Console.WriteLine("{0} has {1} children", apple.Name, apple.NumberOfChildren);
// now try to add apples's children to
// each of the following fruits
List<Fruit> def = new List<Fruit>()
{
new Fruit() { Name = "d" },
new Fruit() { Name = "e" },
new Fruit() { Name = "f" }
};
foreach (Fruit f in def)
{
f.AddFruits(apple.GetFruits());
Console.WriteLine("{0} has {1} children", f.Name, f.NumberOfChildren);
}
Console.Read();
}
Would print:
apple has 3 children
d has 3 children
e has 0 children
f has 0 children
Because apple.GetFruits() will return 0 after the first iteration.
By looking at the custom collection's source, it is hard to realize that _children.Add(f) in AddFruits in fact modifies the fruits previous parent collection.

Categories

Resources