473,396 Members | 1,913 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

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 2511
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: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
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
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
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,...

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.