zeusalmighty
zeusalmighty

Reputation: 1414

c# Implementing two enumerators for the same class

Ok, so here's the basic code:

class foo
{
    String name;
    int property;
}

class bar
{
    private List<foo> a;
    private List<foo> b;
}

I'd like to make it so that calling code can iterate over either list but I want to keep them protected from editing. I've looked into implementing the IEnumarable interface but the problem is that it expects a single "GetEnumerable" definition, but I want two different enumerators. For instance, i want to be able to say

foreach(foo in bar.getA())
{ //do stuff }

and then

foreach(foo in bar.getB())
{ //do stuff }

Do I have to subclass each element and implement the IEnumerable interface over each, and then include THOSE as properties? Am I misunderstanding the IEnumerable interface? I know that the List class has it's own Enumerator, so I could do something like

class bar
{
    private List<foo> a;
    private List<foo> b;

    public IEnumerator<foo> getAEnumerator()
    {  return a.GetEnumerator();

    public IEnumerator<foo> getBEnumerator()
    {  return b.GetEnumerator();

}

but then my for loops look like this:

bar x = new bar();
IEnumerator<foo> y = x.getAEnumerator();
while (y.moveNext())
{
    foo z = y.Current;
} 

so I lose the readability of "foreach".

Is there a way to accomplish using "foreach" over these lists without exposing these lists publicly? I'm still trying to get my head around the IENumerable interface, so maybe I'm missing something obvious.

Upvotes: 0

Views: 519

Answers (2)

Anamta Khan
Anamta Khan

Reputation: 15

class bar
{
    private readonly List<foo> a = new List<foo>();
    private readonly List<foo> b = new List<foo>();

    public IReadOnlyList<foo> A { get {return a.AsReadOnly();}}
    public IReadOnlyList<foo> B { get {return b.AsReadOnly();}}

}

this way you'll not even have to initialize it, and no need to any kind of set

Upvotes: 0

Lucas Trzesniewski
Lucas Trzesniewski

Reputation: 51430

Don't expose a List<T>, expose something else, like an IReadOnlyList<T> instead:

class bar
{
    private readonly List<foo> a = new List<foo>();
    private readonly List<foo> b = new List<foo>();

    public IReadOnlyList<foo> A { get; private set; }
    public IReadOnlyList<foo> B { get; private set; }

    public bar()
    {
        A = a.AsReadOnly();
        B = b.AsReadOnly();
    }
}

Any changes to a and b will reflect in A and B.

Also note that while you can cast a List<T> to an IReadOnlyList<T>, the calling code can cast it back to List<T>. The above method returns a ReadOnlyCollection<T> which provides a safeguard against casting back to a mutable collection type.

The readonly keyword only ensures you don't substitute references to a and b with something else later on.

Upvotes: 2

Related Questions