Error while implementing IEnumerator

67 views Asked by At

I followed the article here and the sample code given in it.

What I am trying to implement is pretty straightfoward. I do have a fair understanding about collections and enumerators. However, what I don't understand is that even though there is hardly any difference in the way I have implemented the code as compared to how it is implemented in the given article, why I am getting an error.

Only difference in the implementation is that the sample code uses T (generic) whereas I am using a class named Address while implementing the custom Addresses collection class.

The code is pretty straightfoward. I have the following classes in the project.

  1. Contact class
  2. Addresses class (Implements custom collection and inherits from ICollection)
  3. Address class
  4. AddressEnumerator

What I wish to achieve is the Dataset like functionality where we can use a syntax like: Dataset ds = new Dataset();

Ds.Tables[0]....blah blah blah.

I get a compile time error in the following method of the AddressEnumerator.cs class. Error: cannot apply indexing with [] to an expression of type ConsoleApplication2.Addresses (Addresses class implements an ICollection)

Compile time error occurs in the following statement: _current = _collection[index];

public bool MoveNext()
    {
        if(++index >= _collection.Count)
        {
            return false;
        }
        else
        {
            _current = _collection[index];
        }
        return true;
    }

Source code:

//following code snippet does not traverse the collection

            foreach (Address a in c.Addresses)
            {
                Console.WriteLine(a.Street);
            }

Program.cs

using System;
using System.Configuration;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
class Program
{
    static void Main(string[] args)
    {

        //RenderTimeSheet();

        Address ad = new Address();

        ad.Street = "Hollywood";
        ad.City = "LA";
        ad.State = "California";
        ad.ZipCode = "93494";
        ad.Country = "USA";


        using (Contact c = new Contact(ad))
        {
            c.FirstName = "John";
            c.LastName = "Doe";

            Console.WriteLine(c.FirstName);
            Console.WriteLine(c.LastName);

            foreach (Address a in c.Addresses)
            {
                Console.WriteLine(a.Street);
            }
        }

        Console.ReadKey();

    }
}

Contact.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;

namespace ConsoleApplication2
{
public class Contact : IDisposable
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Addresses Addresses { get; set; }

    public Contact(Address a)
    {
        Addresses = new Addresses(a);
    }

    public Contact()
    {

    }

    public void Dispose()
    {
        Console.Write("Disposing off...");
    }
}
}

Addresses.cs

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
public class Addresses : ICollection<Address>
{

    private IList<Address> _lstAddress;

    protected bool _IsReadOnly;

    public Addresses(Address _a)
    {
        _lstAddress = new List<Address>();
    }

    public void Add(Address item)
    {

        _lstAddress.Add(item);

    }

    public void Clear()
    {

        _lstAddress.Clear();

    }

    public bool Contains(Address item)
    {
        foreach(Address a in _lstAddress)
        {
            if(a.Street == item.Street)
            {
                return true;
            }
        }
        return false;
    }

    public void CopyTo(Address[] array, int arrayIndex)
    {
        throw new Exception("Not valid for this implementation.");
    }

    public int Count
    {
        get { return _lstAddress.Count; }
    }

    public bool IsReadOnly
    {
        get { return _IsReadOnly; }
    }

    public bool Remove(Address item)
    {
        bool result = false;

        for (int i = 0; i < _lstAddress.Count; i++)
        {
            Address obj = (Address)_lstAddress[i];

            if(obj.Street == item.Street)
            {
                _lstAddress.RemoveAt(i);
                result = true;
                break;
            }
        }
        return result;
    }

    public IEnumerator<Address> GetEnumerator()
    {
        return new AddressEnumerator(this);
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        //throw new NotImplementedException();
        return this.GetEnumerator();
    }
}
}

Address.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
public class Address
{

    public string Street { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
    public string Country { get; set; }
}
}

AddressEnumerator.cs

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

namespace ConsoleApplication2
{
public class AddressEnumerator : IEnumerator<Address>
{
    protected Addresses _collection;

    protected int index;

    protected Address _current;

    public AddressEnumerator()
    {

    }

    public AddressEnumerator(Addresses collection)
    {
        _collection = collection;
        index = -1;
        _current = default(Address);
    }

    public Address Current 
    { 
        get
        {
            return _current;
        } 
    }


    public void Dispose()
    {
        _collection = null;
        _current = default(Address);
        index = -1;
    }

    object System.Collections.IEnumerator.Current
    {
        get 
        {
            return _current;
        }
    }

    public bool MoveNext()
    {
        if(++index >= _collection.Count)
        {
            return false;
        }
        else
        {
            _current = _collection[index];
        }
        return true;
    }

    public void Reset()
    {
        throw new NotImplementedException();
    }
}
}
2

There are 2 answers

6
user287107 On

this is a direct and short solution to your problem, but it is not a "complete clean" solution, also the coding style of the complete implementation should be changed. there are more effective ways implementing enumerable interfaces ...

change the line

_current = _collection[index];

to

_current = _collection._lstAddress[index];

but you also need to change the access modifier

private IList<Address> _lstAddress

for example to

 internal IList<Address> _lstAddress
1
Matthew Watson On

The reason that the sample code works and yours doesn't is because the sample code class BusinessObjectCollection includes this:

public virtual T this[int index]
{
    get
    {
        return (T)_innerArray[index];
    }
    set
    {
        _innerArray[index] = value;
    }
}

which provides the subscript operator [] that your code lacks.

If you add that to your Addresses class (changing _innerArray to _lstAddress) then it should work, I think.