473,473 Members | 2,166 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Re: foreach pretty useless for composite classes, don't ya thunk?

I am not sure what you are asking. You seem to be asking how to implement a
plain IEnumerable on a composite structure, but then your example shows a
flat structure using "yield". Your subject makes me infer that you think
foreach is enirely useless for composite structures.

I will address the subject text, because that makes the most sense to me :-)
Take the following class

public class MyTreeNode : IEnumerable<MyTreeNode>
{
public readonly List<MyTreeNodeChildNodes = new List<MyTreeNode>();
public readonly string Name;
public MyTreeNode ParentNode { get; private set; }

public MyTreeNode(MyTreeNode parentNode, string name)
{
ParentNode = parentNode;
Name = name;
if (parentNode != null)
ParentNode.ChildNodes.Add(this);
}

public string FullName
{
get
{
if (ParentNode == null)
return Name;
else
return ParentNode.FullName + "/" + Name;
}
}

public IEnumerator<MyTreeNodeGetEnumerator()
{
foreach (var node in ChildNodes)
{
yield return node;
foreach (var subNode in node)
yield return subNode;
}
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
it can be used like so....
class Program
{
static void Main(string[] args)
{
var tree = new MyTreeNode(null, "Root");
AddChildNodes(tree, 1, 3);

//********
//NOTE: Foreach not being pretty useless on a composite structure
//********
foreach (var node in tree)
{
Console.WriteLine(node.FullName);
}
Console.ReadLine();
}

static void AddChildNodes(MyTreeNode node, int level, int maxLevel)
{
string[] names = new string[] { "A", "B", "C"};
foreach (var name in names)
{
var childNode = new MyTreeNode(node, name);
if (level < maxLevel)
AddChildNodes(childNode, level + 1, maxLevel);
}

}
}
and it will output the following.....

Root/A
Root/A/A
Root/A/A/A
Root/A/A/B
Root/A/A/C
Root/A/B
Root/A/B/A
Root/A/B/B
Root/A/B/C
Root/A/C
Root/A/C/A
Root/A/C/B
Root/A/C/C
Root/B
Root/B/A
Root/B/A/A
Root/B/A/B
Root/B/A/C
Root/B/B
Root/B/B/A
Root/B/B/B
Root/B/B/C
Root/B/C
Root/B/C/A
Root/B/C/B
Root/B/C/C
Root/C
Root/C/A
Root/C/A/A
Root/C/A/B
Root/C/A/C
Root/C/B
Root/C/B/A
Root/C/B/B
Root/C/B/C
Root/C/C
Root/C/C/A
Root/C/C/B
Root/C/C/C
Does that prove that foreach is useful for composite structures, or have I
completely missed the point of what you were trying to say?

Regards

Pete
Sep 20 '08 #1
4 2520
On Sep 20, 4:14*am, "Peter Morris" <mrpmorri...@SPAMgmail.comwrote:
>
Does that prove that foreach is useful for composite structures, or have I
completely missed the point of what you were trying to say?
Thanks; this was a good example that I've saved to study. Seems a
couple of things are new to me (I've never seen readonly for a list,
only for primitive data like an int, but I guess it makes sense;
likewise 'var' sounds like Visual Basic but it's C#3 compliant I
think), but the main point is that for a "composite" structure (where
I take it a class contains another class as member) uses 'foreach' but
implicitly uses the properties of collections themselves for the
member variable.

To wit:

public IEnumerator<MyTreeNodeGetEnumerator()
{
foreach (var node in ChildNodes)
{
yield return node;
foreach (var subNode in node)
yield return subNode;
}
}

makes use of the property of public readonly List<MyTreeNode>
ChildNodes = new List<MyTreeNode>();
that "List" is a generic container that has its own "behind the
scenes" iterator.

However, as I type this I see that two yield returns are present, but,
I've seen this before and it's legal.

Bottom line: foreach is a useful tool, and once I study this example
more I'll have more to say perhaps, but it's not clear you are really
using 'foreach' any different from the way I currently use it: to
iterate member variables (even classes) that are parts of generic
containers (from the collections library) like List<MyTreeNode>
ChildNodes = new List<MyTreeNode>();

Or maybe that's how you are supposed to use foreach, since these
containers have 'foreach' built in, behind the scenes. Anyway more
later.

RL
Sep 20 '08 #2
couple of things are new to me (I've never seen readonly for a list,
only for primitive data like an int, but I guess it makes sense;
Just saves its reference from changing :-)

likewise 'var' sounds like Visual Basic but it's C#3 compliant
It's just shorthand for writing the class name out twice. I only use it
where it is obvious what the type is.

>However, as I type this I see that two yield returns are present, but,
I've seen this before and it's legal.
yield return 1;
yield return 3;
yield return 5;
yield return 7;

That's legal too, but not much use :-)

>>
Bottom line: foreach is a useful tool, and once I study this example
more I'll have more to say perhaps, but it's not clear you are really
using 'foreach' any different from the way I currently use it:
<<

You *never* use "foreach" differently. "foreach" is just a language
specific way of comsuming the iterator pattern, "yield" is a language
specific way of implementing the iterator pattern. The purpose of the
iterator pattern is to allow you to get access to all *relevant* items in
turn, and not to worry about how those values are obtained. An example is
to get each word within a document for spell checking; these words are held
within various containers (a word, within a paragraph, within a cell, within
a table row, within a table, within a column, within a page, within a
document) - you wouldn't want to write code to loop through all of those,
you just want to iterate all words within the document.
>>
Or maybe that's how you are supposed to use foreach, since these
containers have 'foreach' built in, behind the scenes. Anyway more
later.
<<

Yep. As I just said above, foreach is a consumer of the iterator pattern,
nothing more.

Pete

Sep 20 '08 #3
OK, I am beginning to see now, thanks Peter Morris.

But one more thing: can you tell me how to get rid of this compiler
error?:

foreach statement cannot operate on variables of type
'IEnumerableEx01.Namer' because it implements multiple instantiations
of System.Collections.Generic.IEnumerable<T>'; try casting to a
specific interface instantiation

See the code I will post to Family Tree Mike's reply (since it's his
code, modified).

Almost there (for me), I appreciate it.

BTW your example was good for a n-ary tree that is traversed 'depth
first' recursively rather than 'breath first', and I've put it in my
library as such; thanks again. I already have (from my own work) a
'breath first' non-recursive n-ary tree, so this complements that.

RL

Peter Morris wrote:
>
Yep. As I just said above, foreach is a consumer of the iterator pattern,
nothing more.
Sep 20 '08 #4
On Sep 20, 4:16*pm, raylopez99 <raylope...@yahoo.comwrote:
BTW your example was good for a n-ary tree that is traversed 'depth
first' recursively rather than 'breath first', and I've put it in my
library as such; thanks again. *I already have (from my own work) a
'breath first' non-recursive n-ary tree, so this complements that.
Exactly. And that leads to the next big advantage of the iterator/
enumerator pattern. The collection class itself encapsulates the
logic required to enumerate it's items.
Sep 21 '08 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Matan Nassau | last post by:
This question is a little embarrassing... I have a boolean expressions interpreter with its composite (see Go4's "Design Patterns" book). here is a simple leaf of the composite: class Constant :...
0
by: Michael Andersson | last post by:
Given a set of classes class A { enum [ ID = 0x0001} }; class B { enum [ ID = 0x0002} }; class B { enum [ ID = 0x0004} }; I wish to generate a composite class, perhaps using something like...
32
by: James Curran | last post by:
I'd like to make the following proposal for a new feature for the C# language. I have no connection with the C# team at Microsoft. I'm posting it here to gather input to refine it, in an "open...
13
by: cody | last post by:
foreach does implicitly cast every object in the collection to the specified taget type without warning. Without generics this behaviour had the advantage of less typing for us since casting was...
104
by: cody | last post by:
What about an enhancement of foreach loops which allows a syntax like that: foeach(int i in 1..10) { } // forward foeach(int i in 99..2) { } // backwards foeach(char c in 'a'..'z') { } // chars...
14
by: Josh Ferguson | last post by:
I don't believe a syntax driven equivalent exists for this, but I just thought it would be neat if you could use foreach to do something like this: foreach (Object x in collection1, collection2)...
10
by: fig000 | last post by:
HI, I'm new to generics. I've written a simple class to which I'm passing a generic list. I'm able to pass the list and even pass the type of the list so I can use it to traverse it. It's a...
8
by: =?Utf-8?B?RmFtaWx5IFRyZWUgTWlrZQ==?= | last post by:
An example of a slightly more complicated class might be to have a collection of first names, and a collection of last names in your class. The IEnumerable functions then could return the complete...
8
by: Bill Butler | last post by:
"raylopez99" <raylopez99@yahoo.comwrote in message news:bd59f62a-5b54-49e8-9872-ed9aef676049@t54g2000hsg.googlegroups.com... <snip> I don't think "right" is the correct word. There are many...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
0
muto222
php
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.