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

R

raylopez99

No need.  FTM already posted an example that generates an IEnumerator
that enumerates every combination of first and last names based on two
string arrays (one the holds just first names, and the other holds
just last names).  FTM just happen to use the yield keyword method.
It could have been done by manually declaring and implementing the
IEnumerator but that would be more work.

It also raises the point of the OP--what's the point of
'foreach' (other than eye candy and one somewhat important point)? So
"yield" keyword avoids the awkward IEnumerator inheritance, which I
kind of like, analogous to how delegates are now easier to register
(using 'new') in C#2.0 syntax and/or you don't need to invoke
delegates using .Invoke method--big deal. The "one somewhat important
point" is the one you made: using 'foreach' you can (I think my lingo
is right) do "delayed execution" and/or "lazy execution / evaluation"
and/or you don't need to set up a temporary collection class but can
serially iterate through a collection and get results now, rather than
iterate, get results, store, then output. Fine, that's great and I
agree 'foreach' is great for that. But it's not a big deal IMO* and a
lot of work to get the syntax right.
As for the Dictionary I was focused more on the public interface and
not necessary on how Microsoft made that happen.  I just wanted to
present an example design pattern for case #2.  Fortunately, Microsoft
has made the source code for v3.5 of the framework available.  I'm not
sure about the details for downloading it as I have yet to do that,
but it is available nevertheless.  

Well that's pretty worthless "it's out there"--but not to worry, I
have no intention of going through the code anyway, which is probably
understandable only to the author and an expert with years of C# under
their belt. I have about 2 months C# experience (more with C++) as a
hobbyist, and my goal is to get to the 80% competency level, which I
think I'm there, rather than get into minutiae. Like learning a
language, I want to be conversant in C#, not fluent or to teach the
rules of grammar at university.
Of course, you could always use
Reflector or even ILDASM to examine the framework assemblies.  The
Dictionary class is either in mscorlib.dll or System.dll.

Yeah I notice these .dlls are always popular and have a lot of stuff
in them.

Thanks for your help, it was helpful.

RL

* In other posts I've argued that delegates are a lot of work for the
little they give you, and that inheritance is rarely used by practical
coders in OOP --both of these observations being the exceptions--that
prove the rule--for library code, meaning that for library code indeed
you use delegates and inheritance a lot. I made these observations
before I really knew much about delegates and inheritance, now that I
know a lot more, I see my initial hunch was largely right--though,
that said, I like to use inheritance and delegates in my code because
it's kind of cool (delegates are a sophisticated 'GOTO' statement;
inheritance is another form of nesting/hiding) and it keeps your
skills sharp to use these constructs once in a while so you don't
forget the syntax. I'm sure the same is also true for LINQ, which I
see as a poor man's SQL.
 
P

Peter Morris

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<MyTreeNode> ChildNodes = 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<MyTreeNode> GetEnumerator()
{
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
 
R

raylopez99

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<MyTreeNode> GetEnumerator()
{
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
 
P

Peter Morris

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
 
R

raylopez99

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
 
R

raylopez99

Family Tree Mike-- I went through your example, it was quite good, and
have a question, that I think cuts to my concerns about 'foreach'.

Specifically, I'm trying to return multiple sequences using multiple
IEnumerators / multiple IEnumerable and multiple 'yields', but am
getting 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"

This error only occurs when you try to use 'foreach' in main(), so of
course commenting out 'foreach' in main will 'solve' the problem, but
how do I use 'foreach'? Some sort of cast seems to be in order, but
try as I might I could not get it right. A search on the net found
this close near hit but miss:
http://blogs.msdn.com/ericlippert/a...nce-in-c-part-ten-dealing-with-ambiguity.aspx

I modified your original code to include an array of ints (in addition
to your array of strings).

Rather than talk about it, below is the code, I think you can see
where I'm going.

How to solve this problem? If it can be solved, I take back what I
said about 'foreach' being useless. But, if it cannot be solved, then
my original point stands (this was in fact my original point--that you
should be able to make foreach universal to traverse a complex,
compound class, not just a class with one member variable).

Thanks in advance FTM (or anybody else answering)

RL

//////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace myNamespace1
{
class Program
{
static void Main(string[] args)
{
Namer nlist = new Namer ();
nlist.FirstNames = new string [ ] { "Ray", "Casey",
"Zanaida" };
nlist.LastNames = new string [ ] { "Anthony", "Gonzales",
"Lopez", "Jones" };

//foreach (string s in nlist) //compiler error here
// Console.Out.WriteLine(string.Format("The next name is:
{0}", s));
//Console.In.ReadLine();

}
}
}
//////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace myNamespace1
{
class Namer:IEnumerable<string>,IEnumerable<int> //<--note this
second interface
// everything here compiles correctly, but in main() I cannot use
foreach
{
public string[] FirstNames;
public string[] LastNames;
public int[] iArrNamer; //new member here
public Namer()
{
iArrNamer = new int [2];
iArrNamer[0] = 1;
iArrNamer[1] = 2;
}

IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
for (int idxLast = 0; idxLast < LastNames.Count(); idxLast+
+)
for (int idxFirst = 0; idxFirst < FirstNames.Count();
idxFirst++)
yield return string.Format("{0} {1}",
FirstNames[idxFirst], LastNames[idxLast]);
}

// this GetEnumerator is new
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{

for (int i = 0; i < iArrNamer.Length; i++)
{
yield return iArrNamer;
}

}

System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator()
{
for (int idxLast = 0; idxLast < LastNames.Count(); idxLast+
+)
//BTW ++idxLast (made globally) also works fine, strangely enough
for (int idxFirst = 0; idxFirst < FirstNames.Count();
idxFirst++)
yield return string.Format("{0} {1}",
FirstNames[idxFirst], lastNames[idxLast]);

for (int i = 0; i < iArrNamer.Length; i++)
{
yield return iArrNamer;
}

//compiles OK, since multiple yield returns are allowed, but something
is missing--what?

//I'm trying to return either the string, or, the int, since class
Namer has two member variables, an array of strings and an array of
ints, not just one (originally, there was only an array of strings,
now I've added the array of ints)

}


}
}

//////////////////////////////////////////////////
 
F

Family Tree Mike

Change the code to look like this in your foreach within main:

foreach (string s in ((IEnumerable <string>)nlist))
Console.Out.WriteLine(string.Format("The next name is: {0}", s));

foreach (int i in ((IEnumerable<int>)nlist))
Console.Out.WriteLine(string.Format("The next integer is: {0}", i));


raylopez99 said:
Family Tree Mike-- I went through your example, it was quite good, and
have a question, that I think cuts to my concerns about 'foreach'.

Specifically, I'm trying to return multiple sequences using multiple
IEnumerators / multiple IEnumerable and multiple 'yields', but am
getting 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"

This error only occurs when you try to use 'foreach' in main(), so of
course commenting out 'foreach' in main will 'solve' the problem, but
how do I use 'foreach'? Some sort of cast seems to be in order, but
try as I might I could not get it right. A search on the net found
this close near hit but miss:
http://blogs.msdn.com/ericlippert/a...nce-in-c-part-ten-dealing-with-ambiguity.aspx

I modified your original code to include an array of ints (in addition
to your array of strings).

Rather than talk about it, below is the code, I think you can see
where I'm going.

How to solve this problem? If it can be solved, I take back what I
said about 'foreach' being useless. But, if it cannot be solved, then
my original point stands (this was in fact my original point--that you
should be able to make foreach universal to traverse a complex,
compound class, not just a class with one member variable).

Thanks in advance FTM (or anybody else answering)

RL

//////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace myNamespace1
{
class Program
{
static void Main(string[] args)
{
Namer nlist = new Namer ();
nlist.FirstNames = new string [ ] { "Ray", "Casey",
"Zanaida" };
nlist.LastNames = new string [ ] { "Anthony", "Gonzales",
"Lopez", "Jones" };

//foreach (string s in nlist) //compiler error here
// Console.Out.WriteLine(string.Format("The next name is:
{0}", s));
//Console.In.ReadLine();

}
}
}
//////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace myNamespace1
{
class Namer:IEnumerable<string>,IEnumerable<int> //<--note this
second interface
// everything here compiles correctly, but in main() I cannot use
foreach
{
public string[] FirstNames;
public string[] LastNames;
public int[] iArrNamer; //new member here
public Namer()
{
iArrNamer = new int [2];
iArrNamer[0] = 1;
iArrNamer[1] = 2;
}

IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
for (int idxLast = 0; idxLast < LastNames.Count(); idxLast+
+)
for (int idxFirst = 0; idxFirst < FirstNames.Count();
idxFirst++)
yield return string.Format("{0} {1}",
FirstNames[idxFirst], LastNames[idxLast]);
}

// this GetEnumerator is new
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{

for (int i = 0; i < iArrNamer.Length; i++)
{
yield return iArrNamer;
}

}

System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator()
{
for (int idxLast = 0; idxLast < LastNames.Count(); idxLast+
+)
//BTW ++idxLast (made globally) also works fine, strangely enough
for (int idxFirst = 0; idxFirst < FirstNames.Count();
idxFirst++)
yield return string.Format("{0} {1}",
FirstNames[idxFirst], lastNames[idxLast]);

for (int i = 0; i < iArrNamer.Length; i++)
{
yield return iArrNamer;
}

//compiles OK, since multiple yield returns are allowed, but something
is missing--what?

//I'm trying to return either the string, or, the int, since class
Namer has two member variables, an array of strings and an array of
ints, not just one (originally, there was only an array of strings,
now I've added the array of ints)

}


}
}

//////////////////////////////////////////////////
 
B

Brian Gideon

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.
 
B

Brian Gideon

It also raises the point of the OP--what's the point of
'foreach' (other than eye candy and one somewhat important point)?

Eye candy, syntactical sugar, etc. It's not absoluately necessarily as
you could call the appropriate methods on the IEnumerable/IEnumerator
manually. But, it definitely makes the code easier to read.
 So
"yield" keyword avoids the awkward IEnumerator inheritance, which I
kind of like, analogous to how delegates are now easier to register
(using 'new') in C#2.0 syntax and/or you don't need to invoke
delegates using .Invoke method--big deal.

Yep, again you could write all of the code for the IEnumerator
manually, but the yield keyword avoids all of that.
 The "one somewhat important
point" is the one you made:  using 'foreach' you can (I think my lingo
is right) do "delayed execution" and/or "lazy execution / evaluation"
and/or you don't need to set up a temporary collection class but can
serially iterate through a collection and get results now, rather than
iterate, get results, store, then output.  Fine, that's great and I
agree 'foreach' is great for that.  But it's not a big deal IMO* and a
lot of work to get the syntax right.

Yep. That was exactly my point. I suspect in most cases it's not a
big deal. In fact, I rarely exit out of a foreach before it has
natually completed, but the option is available. I have used this
technique in the past when I wanted to extract the first element of a
SortedDictionary.

object first = null;
foreach (object item in mySortedDictionary.Values)
{
first = item;
exit;
}

SortedDictionary is implemented as a BST. So to extract the first
element you have to keep traversing left until you find it. The code
above will complete in O(log n) time since the traversal exits out
early.

Note, in version 3.5 of the framework there is the First extension
method that likely uses this method, but I'd have to examine the code
or IL to know for sure.
Well that's pretty worthless "it's out there"--but not to worry, I
have no intention of going through the code anyway, which is probably
understandable only to the author and an expert with years of C# under
their belt. I have about 2 months C# experience (more with C++) as a
hobbyist, and my goal is to get to the 80% competency level, which I
think I'm there, rather than get into minutiae.  Like learning a
language, I want to be conversant in C#, not fluent or to teach the
rules of grammar at university.

You might be surprised. Looking at the framework code is not only a
great way to learn industry standard design patterns, but I think it
would also be helpful in learning syntax and techniques specific to
C#. I really don't think you need to be expert to benefit from
looking at the code.
* In other posts I've argued that delegates are a lot of work for the
little they give you, and that inheritance is rarely used by practical
coders in OOP --both of these observations being the exceptions--that
prove the rule--for library code, meaning that for library code indeed
you use delegates and inheritance a lot.  I made these observations
before I really knew much about delegates and inheritance, now that I
know a lot more, I see my initial hunch was largely right--though,
that said, I like to use inheritance and delegates in my code because
it's kind of cool (delegates are a sophisticated 'GOTO' statement;
inheritance is another form of nesting/hiding) and it keeps your
skills sharp to use these constructs once in a while so you don't
forget the syntax.  I'm sure the same is also true for LINQ, which I
see as a poor man's SQL.

Those are all good topics for other threads.
 
R

raylopez99

Change the code to look like this in your foreach within main:

foreach (string s in ((IEnumerable <string>)nlist))
  Console.Out.WriteLine(string.Format("The next name is: {0}", s));

foreach (int i in ((IEnumerable<int>)nlist))
  Console.Out.WriteLine(string.Format("The next integer is: {0}", i));


Thanks FTM, that worked.

BTW, a minor aside, I notice that you 'repeat' GetEnumerator() ***
(see below) rather than use the 'convention', that I've seen in some
books, of this format (for the non-generic IEnumerator, which is
required):

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

But, when I tried this above 'convention' in your code, I could not
compile it, in fact, IntelliSense would not even recognize
GetEnumerator (!). So I wonder if you've come across this.
However,it's not a big deal since I just use your convention and it
works fine.

Thanks again,

RL

***

System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator()
{
for (int idxLast = 0; idxLast < LastNames.Count(); idxLast
+
+)
//BTW ++idxLast (made globally) also works fine, strangely enough
for (int idxFirst = 0; idxFirst < FirstNames.Count();
idxFirst++)
yield return string.Format("{0} {1}",
FirstNames[idxFirst], lastNames[idxLast]);

for (int i = 0; i < iArrNamer.Length; i++)
{
yield return iArrNamer;
}
 
F

Family Tree Mike

Yes, I have noted what you said too. I believe it is because the
GetEnumerator()
is not a callable thing. It is used from the foreach context as has been
noted. You
don't really call it from the code. Hopefully one of the other folks can
explain the
details of why the method itself isn't callable. I just found an example
that I follow
and have continued on the tradition, so to speak...

Change the code to look like this in your foreach within main:

foreach (string s in ((IEnumerable <string>)nlist))
Console.Out.WriteLine(string.Format("The next name is: {0}", s));

foreach (int i in ((IEnumerable<int>)nlist))
Console.Out.WriteLine(string.Format("The next integer is: {0}", i));


Thanks FTM, that worked.

BTW, a minor aside, I notice that you 'repeat' GetEnumerator() ***
(see below) rather than use the 'convention', that I've seen in some
books, of this format (for the non-generic IEnumerator, which is
required):

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

But, when I tried this above 'convention' in your code, I could not
compile it, in fact, IntelliSense would not even recognize
GetEnumerator (!). So I wonder if you've come across this.
However,it's not a big deal since I just use your convention and it
works fine.

Thanks again,

RL

***

System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator()
{
for (int idxLast = 0; idxLast < LastNames.Count(); idxLast
+
+)
//BTW ++idxLast (made globally) also works fine, strangely enough
for (int idxFirst = 0; idxFirst < FirstNames.Count();
idxFirst++)
yield return string.Format("{0} {1}",
FirstNames[idxFirst], lastNames[idxLast]);

for (int i = 0; i < iArrNamer.Length; i++)
{
yield return iArrNamer;
}
 
B

Brian Gideon

Family Tree Mike-- I went through your example, it was quite good, and
have a question, that I think cuts to my concerns about 'foreach'.

Specifically, I'm trying to return multiple sequences using multiple
IEnumerators / multiple IEnumerable and multiple 'yields', but am
getting 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"

This error only occurs when you try to use 'foreach' in main(), so of
course commenting out 'foreach' in main will 'solve' the problem, but
how do I use 'foreach'?  Some sort of cast seems to be in order, but
try as I might I could not get it right.  A search on the net found
this close near hit but miss:http://blogs.msdn.com/ericlippert/archive/2007/11/09/covariance-and-c...

The problem you are experiencing here is the result using explicit
interface implementations as opposed to implicit. But, if you're
going declare more than one GetEnumerator method then all but one must
be explicitly implemented because they all have the same signature.

Instead of declaring multple GetEnumerator methods that return
IEnumerator objects why not declare different methods with different
names that return IEnumerable objects. When used in a member that
returns an IEnumerable the yield keyword will cause the compiler to
automatically generate an appropriate IEnumerable and IEnumerator
combination. That's the general pattern I was referring to when I
metioned the Dictionary.Values and Dictionary.Keys properties in
another post.
 
R

raylopez99

Brian said:
Instead of declaring multple GetEnumerator methods that return
IEnumerator objects why not declare different methods with different
names that return IEnumerable objects. When used in a member that
returns an IEnumerable the yield keyword will cause the compiler to
automatically generate an appropriate IEnumerable and IEnumerator
combination. That's the general pattern I was referring to when I
metioned the Dictionary.Values and Dictionary.Keys properties in
another post.

Like so many things in programming, without a specific example it's a
no-go. Just tried various permuations and it won't work.

If it's simple enough to show please show us.

Otherwise I'll stick to FTM's convention, which works and is not an
eyesore to me.

RL
 
B

Brian Gideon

Like so many things in programming, without a specific example it's a
no-go.  Just tried various permuations and it won't work.

If it's simple enough to show please show us.

Otherwise I'll stick to FTM's convention, which works and is not an
eyesore to me.

RL

Understood. Here's the shortest possible example I could come up with
to demonstrate everything you want to do. That is...define iterators
that enumerate the constituent variables of a composite class 1)
individually and 2) together. Notice that I use the yield keyword in
the context of members that return IEnumerable instead of
IEnumerator. I think with this example you'll see the power and
elegance behind the IEnumerator/IEnumerable/foreach pattern.

class Program
{
static void Main(string[] args)
{
MyCollection a = new MyCollection();

foreach (string name in a.FirstOnly)
{
Console.WriteLine(name);
}

foreach (string name in a.LastOnly)
{
Console.WriteLine(name);
}

foreach (string name in a.Combination)
{
Console.WriteLine(name);
}
}
}

public class MyCollection
{
private string[] m_First = { "Brian", "Ray" };
private string[] m_Last = { "Gideon", "Lopez" };

public MyCollection()
{
}

public IEnumerable<string> FirstOnly
{
get
{
foreach (string name in m_First)
{
yield return name;
}
}
}

public IEnumerable<string> LastOnly
{
get
{
foreach (string name in m_Last)
{
yield return name;
}
}
}

public IEnumerable<string> Combination
{
get
{
foreach (string first in m_First)
{
foreach (string last in m_Last)
{
yield return first + " " + last;
}
}
}
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top