Ошибка при реализации IEnumerator

Я следовал за этой статьей и приведенным в ней примером кода.

То, что я пытаюсь реализовать, довольно просто. У меня есть четкое представление о коллекциях и счетчиках. Однако чего я не понимаю, так это того, что, несмотря на то, что способ реализации кода практически не отличается от того, как он реализован в данной статье, я получаю сообщение об ошибке.

Единственное отличие в реализации состоит в том, что в примере кода используется T (универсальный), тогда как я использую класс с именем Address при реализации пользовательского класса коллекции адресов.

Код довольно прост. У меня есть следующие классы в проекте.

  1. Контактный класс
  2. Класс адресов (реализует пользовательскую коллекцию и наследует от ICollection)
  3. Адресный класс
  4. AddressEnumerator

Чего я хочу добиться, так это функциональности, подобной Dataset, где мы можем использовать такой синтаксис, как: Dataset ds = new Dataset ();

Ds.Tables [0].... бла-бла-бла.

Я получаю ошибку времени компиляции в следующем методе класса AddressEnumerator.cs. Ошибка: невозможно применить индексирование с помощью [] к выражению типа ConsoleApplication2.Addresses (класс Addresses реализует ICollection)

Ошибка времени компиляции возникает в следующем операторе: _current = _collection[index];

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

Исходный код:

// следующий фрагмент кода не пересекает коллекцию

            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 ответа

Это прямое и краткое решение вашей проблемы, но это не "полностью чистое" решение, также следует изменить стиль кодирования полной реализации. Есть более эффективные способы реализации перечислимых интерфейсов...

изменить линию

_current = _collection[index];

в

_current = _collection._lstAddress[index];

но вам также нужно изменить модификатор доступа

private IList<Address> _lstAddress

например, чтобы

 internal IList<Address> _lstAddress

Причина того, что пример кода работает, а ваш нет, заключается в том, что пример кода класса BusinessObjectCollection включает в себя это:

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

который обеспечивает оператор индекса [] что ваш код не хватает.

Если вы добавите это к вашему Addresses класс (меняется _innerArray в _lstAddress) тогда должно работать, я думаю.

Другие вопросы по тегам