Below is a first attempt at using a Composite pattern.
It works in the sense that I can arbitrarily nest and get the correct results for the Duration property, with is the focus of the composition. BUT has a coding problem in that the iteration over the children needed to output the composite's ToString() fails:
System.InvalidOperationException : Collection was modified; enumeration operation may not execute.
The are a few extension methods for GetDescendents in this posting, including one that uses a stack to avoid the expense of recursion and
nested iterators.
I would like to understand the pattern better first though, so I have a few questions here:
How can I change the existing iteration code to prevent this error? I know how to convert it to a Linq equivalent but I want to leave it as the loops until I understand what is wrong with it.
Is it typical in the Composite to provide a Count property, or somehow cache the count after an iteration?
in the general case where you don't need a specialized collection, would you typically have your Children property be IEnumerable, IList, or List?
Any good links for examples of working (non-trival) .net code would also be much appreciated.
Cheers,
Berryl
CODE
public interface IComponent {
void Adopt(IComponent node);
void Orphan(IComponent node);
TimeSpan Duration { get; }
IEnumerable<IComponent> Children { get; }
}
public class Allocation : Entity, IAllocationNode {
public void Adopt(IAllocationNode node) { throw new InvalidOperationException(_getExceptionMessage("Adopt", this, node)); }
public void Orphan(IAllocationNode node) { throw new InvalidOperationException(_getExceptionMessage("Orphan", this, node)); }
public IEnumerable<IAllocationNode> Allocations { get { return Enumerable.Empty<IAllocationNode>(); } }
public virtual TimeSpan Duration { get; set; }
}
class MyCompositeClass : IAllocationNode {
public MyCompositeClass() { _children = new List<IAllocationNode>(); }
public void Adopt(IAllocationNode node) { _children.Add(node); }
public void Orphan(IAllocationNode node) { _children.Remove(node); }
public TimeSpan Duration {
get {
return _children.Aggregate(TimeSpan.Zero, (current, child) => current + child.Duration);
}
}
public IEnumerable<IAllocationNode> Children {
get {
var result = _children;
foreach (var child in _children) {
var childOnes = child.Children;
foreach (var node in childOnes) {
result.Add(node);
}
}
return result;
}
}
private readonly IList<IAllocationNode> _children;
#endregion
public override string ToString() {
var count = Children.Count();
var hours = Duration.TotalHours.ToString("F2");
return string.Format("{0} allocations for {1} hours", count, hours);
}
}
How can I change the existing
iteration code to prevent this error?
The exception is occurring because the code in the Children property's getter is modifying a collection while iterating over it.
You appear to be under the impression that the code
var result = _children;
creates a copy of the list referred to by the _children field. It does not, it just copies the reference to the list (which is what the value of the field represents) to the variable.
An easy fix to copy the list over is to instead do:
var result = _children.ToList();
I know how to convert it to a Linq
equivalent.
The LINQ equivalent of your current code, which should work in a lazy manner, is:
return _children.Concat(_children.SelectMany(child => child.Children));
EDIT:
I was originally under the impression that your code was limiting the traversal-depth to two levels (children and grandchildren), but now I can see that this is not the case: there is indeed a recursive call to the property Children rather than just the value of the field _children. This naming is quite confusing because the property and the 'backing' field represent different things entirely. I strongly recommend that you rename the property to something more meaningful, such as Descendants.
Related
Given an Object as Such
public class Thing
{
public Thing() { this.children = new List<Thing>();}
public int Id {get; set;}
public string Name {get; set;}
public List<Thing> children{ get; set;}
public string ToString(int level = 0)
{
//Level is added purely to add a visual hierarchy
var sb = new StringBuilder();
sb.Append(new String('-',level));
sb.AppendLine($"id:{Id} Name:{Name}");
foreach(var child in children)
{
sb.Append(child.ToString(level + 1));
}
return sb.ToString();
}
}
and if used (abused!?) in such a way
public static void Main()
{
var root = new Thing{Id = 1,Name = "Thing1"};
var thing2 = new Thing{Id = 2,Name = "Thing2"};
var thing3 = new Thing{Id = 3,Name = "Thing3"};
root.children.Add(thing2);
thing2.children.Add(thing3);
thing3.children.Add(root); //problem is here
Console.WriteLine(root.ToString());
}
how does one be defensive about this kind of scenario.
This code as it stands produces a stackoverflow, infinite recursion, or memory exceeded error.
In a (IIS) website this was causing the w3 worker processes to crash, and eventually the app pool to shut down (Rapid-Fail Protection)
The code above is indicative only to reproduce the problem. In the actual scenario, the structure is coming from a database with Id and ParentId.
Database table structure similar to
CREATE TABLE Thing(
Id INT NOT NULL PRIMARY KEY,
Name NVARCHAR(255) NOT NULL,
ParentThingId INT NULL //References self
)
The issue is that the creation of the 'things' by users is not preventing a incestuous relationship (i.e. a Parent could have children (who could have children etc.... that one eventually points at the parent again). One could put a constraint on the db to prevent the thing not being its own parent (makes sense), but depending on depth this could get ugly, and there is some argument that a circular reference may be required (we are still debating this....)
So arguably the structures can be circular, but if you want to render this kind of structure on a web page say as a <ul><li><a> tag kind of thing in a parent/child menu, how does one become proactive about dealing with this user generated data issue in code?
.NET fiddle here
One way would be to include a collection of visited nodes in the recursive call. If visited before you are in a cycle.
public string ToString(int level = 0, HashSet<int> visited)
{
foreach(var child in children)
{
if(visited.Add(child.Id))
sb.Append(child.ToString(level + 1, visited));
else
//Handle the case when a cycle is detected.
}
return sb.ToString();
}
You can unfold the tree structure by putting each element on a stack or queue and popping items of there while the collection has items. In the while loop you put the children of each item on the queue.
If you care about the level of the item in the tree you need can use a helper object that stores that.
Edit:
While unfolding the tree you can put each item on a new list and use that as reference for circular problems.
If you can a) eliminate that possibility of wanting to have circular references and b) guarantee that all children are already known of when that parent is created, its a great opportunity to make children an immutable collection that's only set via the constructor.
That gives you a class that, by structural recursion, you know cannot contain any loops, no matter how big the overall structure is. Something like:
public sealed class Thing
{
public Thing(IEnumerable<Thing> children) {
this._children = children.ToList().AsReadOnly();
}
private readonly ReadOnlyCollection<Thing> _children;
public int Id {get; set;}
public string Name {get; set;}
public IEnumerable<Thing> children {
get {
return _children;
}
}
public string ToString(int level = 0)
{
//Level is added purely to add a visual hierarchy
var sb = new StringBuilder();
sb.Append(new String('-',level));
sb.AppendLine($"id:{Id} Name:{Name}");
foreach(var child in children)
{
sb.Append(child.ToString(level + 1));
}
return sb.ToString();
}
}
Now, of course, those conditions I have stated above are quite big "if"s, so you need to consider whether it's a good fit for you.
In general terms, a program I'm making involves storing a small number of entries (probably less than 30 at any given time) which can be categorized. I want to allow these entries to be seen but not altered from outside the class using them. I made a class called Entry which could be modified and another called ReadOnlyEntry which is a wrapper for an Entry object. The easiest way to organize these Entry objects it seems is to create a List<List<Entry>>, where each List<Entry> is a category. But then exposing that data in a readonly way became messy and complicated. I realized I would have to have one object of each of the following types:
List<List<Entry>> data;
List<List<ReadOnlyEntry>> // Where each ReadOnlyEntry is a wrapper for the Entry in the same list and at the same index as its Entry object.
List<IReadOnlyCollection<ReadOnlyEntry>> // Where each IReadOnlyCollection is a wrapper for the List<ReadOnlyEntry> at the same index in data.
IReadOnlyCollection<IReadOnlyCollection<ReadOnlyList>> readOnlyList // Which is a wrapper for the first item I listed.
The last item in the list would be exposed as public. The first lets me change entries, the second lets me add or delete entries, and the third lets me add or delete categories. I would have to keep these wrappers accurate whenever the data changes. This seems convoluted to me, so I'm wondering if there's a blatantly better way to handle this.
Edit 1:
To clarify, I know how to use List.asReadOnly(), and the stuff I proposed doing above will solve my problem. I'm just interested in hearing a better solution. Let me give you some code.
class Database
{
// Everything I described above takes place here.
// The data will be readable by this property:
public IReadOnlyCollection<IReadOnlyCollection<ReadOnlyList>> Data
{
get
{
return readOnlyList;
}
}
// These methods will be used to modify the data.
public void AddEntry(stuff);
public void DeleteEntry(index);
public void MoveEntry(to another category);
public void AddCategory(stuff);
public void DeleteCategory(index);
}
You can use List<T>.AsReadOnly() to return ReadOnlyCollection<T>.
Also, you're torturing the List<T> class storing the data the way you are. Build your own hierarchy of classes which store your individual lists.
.NET collections should support covariance, but they don't support it themselves (instead some interfaces support covariance https://msdn.microsoft.com/ru-ru/library/dd233059.aspx). Covariance means List<Conctrete> behaves like subclass of List<Base> if Concrete is subclass of Base. You can use interfaces covariation or just use casting like this:
using System.Collections.Generic;
namespace MyApp
{
interface IEntry
{
}
class Entry : IEntry
{
}
class Program
{
private List<List<Entry>> _matrix = null;
public List<List<IEntry>> MatrixWithROElements
{
get
{
return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry));
}
}
public IReadOnlyList<List<IEntry>> MatrixWithRONumberOfRows
{
get
{
return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry));
}
}
public List<IReadOnlyList<IEntry>> MatrixWithRONumberOfColumns
{
get
{
return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry) as IReadOnlyList<IEntry>);
}
}
public IReadOnlyList<IReadOnlyList<IEntry>> MatrixWithRONumberOfRowsAndColumns
{
get
{
return _matrix.ConvertAll(row => row.ConvertAll(item => item as IEntry));
}
}
public void Main(string[] args)
{
}
}
}
Thanks to Matthew Watson for pointing on errors in my previous answer version.
You could make an interface for Entry which contains only getters; you would expose elements via this interface to provide read-only access:
public interface IEntry
{
int Value { get; }
}
The writable implementation would be simply:
public sealed class Entry : IEntry
{
public int Value { get; set; }
}
Now you can take advantage of the fact that you can return a List<List<Entry>> as a IReadOnlyCollection<IReadOnlyCollection<IEntry>> without having to do any extra work:
public sealed class Database
{
private readonly List<List<Entry>> _list = new List<List<Entry>>();
public Database()
{
// Create your list of lists.
List<Entry> innerList = new List<Entry>
{
new Entry {Value = 1},
new Entry {Value = 2}
};
_list.Add(innerList);
}
public IReadOnlyCollection<IReadOnlyCollection<IEntry>> Data => _list;
}
Note how simple the implementation of the Data property is.
If you need to add new properties to IEntry you would also have to add them to Entry, but you wouldn't need to change the Database class.
If you're using C#5 or earlier, Data would look like this:
public IReadOnlyCollection<IReadOnlyCollection<IEntry>> Data
{
get { return _list; }
}
Is there a smarter way of protecting foreach loops against NullReference exceptions than this:
if (G_Locatie.OverdrachtFormulierList != null)
{
foreach (OverdrachtFormulier otherform in G_Locatie.OverdrachtFormulierList)
{
...
}
}
I use a lot of foreach loops, often nested, and a lot of variables where e.g. G_Location certainly exists, but datamember .OverdrachtFormulierList may not have been assigned a list use new yet.
Dear friends, thanks for all your comments. After getting the idea of your suggestions, while having a lot of trouble understanding exactly, after digging through the Lasagna code I got to work on, and after some experimentation, I found that the easiest and cleanest way is to simply avoid having the NULL, by proper initialization. While I kind of resist having to initialize the OverdrachtFormulierList in my code, with the risk of forgetting one instance, I found the proper place for initialization, namely in the original class definition.
For simplicity, look at this code:
class MyClass
{
public List<string> items = new List<string>();
public IEnumerator<string> GetEnumerator()
{
return items.GetEnumerator();
}
}
class MyComplexClass
{
private MyClass _itemlist /*= new MyClass()*/;
public MyClass itemlist
{
get { return _itemlist; }
set { _itemlist = value; }
}
}
void Sandbox()
{
MyClass mc /*= new MyClass()*/;
foreach (string Sb in mc.items)
{
string x = Sb;
}
MyComplexClass mcc = new MyComplexClass();
foreach (string Mb in mcc.itemlist) // <--- NullReferenceException
{
string x = Mb;
}
return;
}
The fun thing is that C# seems to protect you from a lot of buggy mistakes. This code will not build if you do not uncomment the initialization in Sandbox(), so the first foreach will not get a NullReferenceException.
However, you'd better uncomment the init in MyComplexClass to avoid the exception in the second foreach. C# will build with and without this initialization.
So it turns out that in my real code I just have to add a simple initialization in the Class definition of G_Locatie.
The only issue now is that I always wanted to simplify the above code with {get; set;} but that would not be possible with the initialization as described. I will have to live with that minor issue.
In fact, on object-type properties, you don't really need the setter.
Finally, I realized that I could not find a proper title for my problem. So far, every problem I had was already answered in this forum, and I feel that I had to post today only because I could not find posts similar to this one. Perhaps someone can come up with title and tags that make this solution better findable.
Yes, your collection properties should return empty collections rather than null. One way you can ensure this is by using a backing field and assigning a new list in the getter:
private List<string> overdrachtFormulierList;
public List<string> OverdrachtFormulierList
{
get
{
return this.overdrachtFormulierList ??
(this.overdrachtFormulierList = new List<string>());
}
set
{
this.overdrachtFormulierList = value;
}
}
You can also use Enumerable.Empty<T> if your types are IEnumerable<T>
One option would be to create an extension method:
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable source)
{
return source ?? Enumerable.Empty<T>();
}
Then:
foreach (var otherform in G_Locatie.OverdrachtFormulierList.EmptyIfNull())
{
...
}
It would still be preferable to always use an empty collection instead of a null reference, mind you.
I have an existing application with objects like so.
class MyObject{
public MyCollection TypeOnes;
public MyCollection TypeTwos;
public MyCollection TypeThrees;
public MyCollection All;
}
class MyCollection : Collection{
public boolean IsLoaded;
}
And it is loaded like this.
//using bool array for flag simplicity in example
public void Load(ref MyObject obj, bool[] flags){
if(flags[0]){
obj.TypeOnes = LoadOnes();
obj.TypeOnes.IsLoaded = true;
}else{
obj.TypeOnes = new MyCollection();
}
if(flags[1]){
obj.TypeTwos = LoadTwos();
obj.TypeTwos.IsLoaded = true;
}else{
obj.TypeTwos= new MyCollection();
}
if(flags[2]){
obj.TypeThrees = LoadThrees();
obj.TypeThrees.IsLoaded = true;
} else {
obj.TypeThrees = new MyCollection();
}
if(flags[3]){
obj.All = obj.TypeOnes.Clone().AddRange(obj.TypeTwos.Clone()).AddRange(obj.TypeThrees.Clone());
obj.All.IsLoaded = true;
} else {
obj.All = new MyCollection();
}
}
As you can plainly see the All collection that is supposed to represent all of the Types will be out of sync unless all types are loaded at once with the All collection.
What I'm going to do is make a single flag to load all of the type collections, however, I would like to keep the All collection to use to access all of the Type Collections at once and have them in sync in order to limit the amount of refactoring I'm going to have to do. I want it to be read/write so that if I make a change to the TypeOnes collection it will be reflected in the All collection and vice versa.
Is there an existing DataType that I can use for this?
If not what kind of data structure am I looking to build?
Unless you have a specific reason to create a clone of the objects in the three contained collection, why not implement All as an IEnumerable<T> (or IEnumerable if you're using pre-generic .NET), something like:
// Option: Preserve duplicates between collections
public IEnumerable<T> All()
{
// Ensure child collections are loaded
return TypeOnes.Concat(TypeTwos).Concat(TypeThrees);
}
// Option remove duplicates between collections
public IEnumerable<T> All()
{
// Ensure child collections are loaded
return TypeOnes.Union(TypeTwos).Union(TypeThrees);
}
That way the existing code contract for adding things to the contained collections is maintained, and you are ensured that All is never stale or out of sync with those collections.
Note that with the old code contract, All became out of sync with the contained collections after it was initialized (since updates to the children were not reflected into All). This is a change in behavior that may or may not be acceptable.
How about something like this? Concat will merge the collections and return all of them at once.
class MyObject
{
public MyCollection TypeOnes;
public MyCollection TypeTwos;
public MyCollection TypeThrees;
public IEnumerable<T> All
{
get { return TypeOnes.Concat(TypeTwos.Concat(TypeThrees));}
// You can use Union() to handle duplicates as well, but it's slower.
}
}
Possible approach - expose "all" as IEnumerable<Base_type_for_items_in_other_collections> and create it on demand by concatenating other collections. I.e. if you have small list of collections basic Enumerable.Concat would work:
public IEnumerabe<MyObject> All {get
{
return TypeOnes.Concat(TypeTwos.Concat(TypeThrees));
}}
All you really need is an ICollection interface or IEnumerable interface that covers all your other collections in a union, right? I assume you won't be adding items to the All collection once you've loaded everything. If that's the case, try:
For the declaration of All:
public IEnumerable<MyBaseType> All;
To set All:
obj.All = System.Linq.Enumerable.Concat<MyBaseType>(
obj.TypeOnes, obj.TypeTwos).Concat(obj.TypeThrees);
That should allow All to reflect changes in the other collections even if it doesn't allow you to add items directly to it.
Since there might be a lot of items you can consider yield return to return items so caller can stop accessing items when appropriate limit were reached/item was found.
public class MyObject
{
public MyCollection TypeOnes { get; set;}
public MyCollection TypeTwos { get; set;}
public MyCollection TypeThrees { get; set;}
public IEnumerable<string> All
{
get
{
foreach (var item in TypeOnes.Union(TypeTwos).Union(TypeThrees))
{
yield return item;
}
}
}
}
public class MyCollection : Collection<string>
{
public bool IsLoaded { get; set; }
}
Is there anything wrong with defining something like this:
class ObjectA
{
property a;
property b;
List <ObjectA> c;
...
}
No, and because the answer needs at least 30 characters, I'll add that this is a common pattern.
Since you included the oop tag, though, I'll add that this pattern gives a lot of control to the outside world. If c is a list of children, for example, you're giving everyone who has access to an instance of ObjectA the ability to add, delete, or replace its children.
A tighter approach would be to use some sort of read-only type (perhaps implementing IList<ObjectA>) to expose the children.
EDIT
Note that the following still allows others to modify your list:
class ObjectA
{
property a;
property b;
List <ObjectA> c;
...
public List<ObjectA> Children { get { return c; } }
}
The absence of a setter only prevents outsiders from replacing the list object.
Nope. That's perfectly acceptable. Tree structures do this.
It is perfectly valid. For example, you would have to do something like this to build a tree data structure (parent node contains a list of child nodes).
i have to ask if your question is about putting a List< > in there, or if it is about putting a List< ObjectA > inside of ObjectA. and the answer to both questions is "Yes"!
the thing to keep in mind is that by default, the access is private. if you want other classes to use this list, then you need to add a few things to your class...
class ObjectA
{
property a;
property b;
List <ObjectA> c;
// allow access, but not assignment
// you can still modify the list from outside, you just cant
// assign a new list from outside the class
public List<ObjectA> somePropertyName{ get { return this.c;}}
// same as above, only allow derived child classes to set the list
public List<ObjectA> somePropertyName{ get { return this.c;}
protected set { this.c = value;} }
// allow all access
public List<ObjectA> somePropertyName{ get { return this.c;}
set { this.c = value;} }
}
No. This is valid. Many structures uses this graph like pattern.
If you eg have a base collection class
namespace MiniGraphLibrary
{
public class GraphCollection
{
public Node Root { set; get; }
public Node FindChild(Node root)
{
throw new NotImplementedException();
}
public Node InsertNode(Node root, Node nodeToBeInserted)
{
throw new NotImplementedException();
}
}
}
Then you can have the node act like this:
namespace MiniGraphLibrary
{
public class Node
{
private string _info;
private List<Node> _children = new List<Node>();
public Node(Node parent, string info)
{
this._info = info;
this.Parent = parent;
}
public Node Parent { get; set; }
public void AddChild(Node node)
{
if (!this.DoesNodeContainChild(node))
{
node.Parent = this;
_children.Add(node);
}
}
public bool DoesNodeContainChild(Node child)
{
return _children.Contains(child);
}
}
}
Note that this is something I wrote in 2 minutes, and it is problery not good in production, but the 2 main things is that you have a parent node and many children. When you add a child node to a given node, then you make sure that it has its parent node set. Here I first check if the child is allready in the children list before connection the two.
You could make some changes to the code, and make sure that if a child is removed an parent lists that it is allready connected to. I have not done this there.
I have made this to illustrate how it could be used. And it is used many places. Fx clustered indexes in MSSQL uses some sort of this tree like representation. But I am NOT an expert on this subject, so correct me if I am wrong.
I have not implemented the two classes in the GraphCollection class. The downside of my little example is that you if you are going to implement the Find method, then you have to go through the whole graph. You could make a binary tree that only has two children:
namespace MiniTreeLibrary
{
public class SimpleNode
{
private string _info;
private SimpleNode _left;
private SimpleNode _right;
private SimpleNode _parent;
public SimpleNode(Node parent, string info)
{
this._info = info;
this.Parent = parent;
}
public Node Parent { get; private set; }
}
}
I have omitted the insertion of the right and left. Now with this binary tree you could do some pretty darn fast searching, if you wanted!! But that is another discossion.
There is many rules when it comes trees and graphs, and my graph is even a real graph. But I have put these examples here so you can see that it is used alot!! If you want to go more into linear and other data structures, then see this serie of articles. Part 3, 4 and 5 they talks alot more about trees and graphs.