Реализуйте IEnumerable в свойстве - PullRequest
3 голосов
/ 18 октября 2010

Принимая класс

public class Foo 
{
    public List<Bar> Bar = new List<Bar>();
    public string Something;
    public TStatus Status;
}

Бар - это класс, определенный как

public class Bar
{
    public string Code;
    public string Message;
    public TStatus Status;
}

Мне нужно перебрать панель списка, но я не могу использовать foreach, потому что мне нужно реализовать IEnumerable. Я новичок, и мне трудно разобраться, как его реализовать, любая помощь приветствуется.

Ответы [ 8 ]

11 голосов
/ 18 октября 2010

Пара вещей:

1.) Что касается вашего фактического вопроса , у вас есть два варианта:

Вы можете перебрать поле Bar (или свойство, если вы измените его на свойство, как описано ниже) в вашем коде:

Foo foo = new Foo();

foreach(Bar bar in foo.Bar)
{
    ...
}

Или вы можете Foo реализовать IEnumerable<Bar> (это более сложно):

public class Foo : IEnumerable<Bar>
{
    .. your existing code goes here

    public IEnumerator<Bar> GetEnumerator()
    {
        return Bar.GetEnumerator();
    }

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

Это позволит вам сделать это:

Foo foo = new Foo();

foreach(Bar bar in foo)
{

}

Лично я бы порекомендовал первый вариант. Это проще, и если Foo действительно не является (а не просто имеет ) коллекцию Bar объектов, то это кажется более интуитивным.

2.) То, что у вас есть выше, не является свойствами, это открытые поля. Свойство имеет геттер и сеттер и выглядит примерно так:

public class Foo
{
    public string Something
    {
        get { return ...; }
        set { ... = value; }
    }
}

Свойства обычно работают с одной переменной, называемой резервным хранилищем. Для вышеуказанного свойства, что-то вроде этого:

public class Foo
{
    private string something;

    public string Something
    {
        get 
        { 
            return something; 
        }
        set  
        { 
            something = value; 
        }
    }
}

Строго говоря, вы можете поместить абсолютно любой блок кода, который возвращает строку, в блок get, и вы можете поместить что угодно в блок set (включая ничего, хотя это не очень хорошая идея).

Свойства позволяют вам определять что-то, что ведет себя как поле (поскольку вы можете назначить это с помощью знака равенства), но использует поведение, которое вы указываете, когда его значение извлекается или устанавливается. Однако одна из проблем с очень простыми свойствами (которые просто получают / устанавливают переменную поддержки без какой-либо другой логики) заключается в том, что она немного многословна для того, что она на самом деле делает. Вот почему в C # 3.0 была введена концепция автоматических свойств, которая выглядит следующим образом:

public class Foo
{
    public string Something { get; set; }
}

Здесь Something выглядит немного как поле, но на самом деле это свойство. Компилятор C # распознает этот синтаксис (заменяя блоки кода для get и set только точкой с запятой) и создает для вас вспомогательную переменную и вставляет код для чтения из него и записи в него.

2 голосов
/ 18 октября 2010

Кстати, если вы хотите, чтобы они были свойствами, сделайте поля приватными, так что:

private List<Bar> _bar = new List<Bar>();


public IEnumerable<Bar> Bar 
{
    get { return _bar; }
}

Сохраняет его во многих других контекстах.

2 голосов
/ 18 октября 2010

Вы можете сделать это так:

var foo = new Foo();
foo.Bar.Add(new Bar {Code = "code1" });
foo.Bar.Add(new Bar {Code = "code2" });

foreach(var b in foo.Bar)
{
     Console.WriteLine(b.Code);
}
1 голос
/ 18 октября 2010

Я сделаю здесь прыжок, и вы пытаетесь добавить свойство в свой класс Foo, которое возвращает IEnumerable или IEnumerable<Bar>, и что это свойство должно выполнять какую-то фильтрацию.в списке Bar объектов, содержащихся в поле Foo.Bar.

РЕДАКТИРОВАТЬ: Если это не похоже на то, что вы пытаетесь сделать, то этот ответ может быть не для вас.Пожалуйста, не позволяйте моему ответу привести вас к дальнейшей путанице.

Вот мои предположения о проблеме:

  1. Оба Foo и Bar являются вложенными классами в другом классеи TStatus является универсальным параметром для содержащего класса.
  2. Вы хотите добавить свойство к Foo, которое возвращает коллекцию Bar объектов, которые имеют свойство Status, равное Foo свойство объекта Status.Я просто делаю здесь предположение, но я подумал, что это может быть причиной того, что у вас есть свойство Status для Foo и Bar.

Ниже приведена полная реализация, которая предоставляетBarsFilteredByStatus свойство класса Foo.При этом используется итератор .NET для предоставления отфильтрованной коллекции Bar объектов, где Bar.Status равно Foo.Status.Если это похоже на то, что вам нужно, тогда возьмите этот код и поиграйте с ним.

// an example status enum
enum SomeStatus
{
    Open,
    Closed,
    Funky,
}

// Blarg<TStatus> is just some container class.  This isn't necessary, but it allows TStatus to be a generic parameter rather than a specific type.
class Blarg<TStatus>
{
    public class Bar
    {
        public string Code;
        public string Message;
        public TStatus Status;
    }

    public class Foo
    {
        public List<Bar> Bar = new List<Bar>();
        public string Something;
        public TStatus Status;

        public IEnumerable<Bar> BarsFilteredByStatus
        {
            get
            {
                // return a filtered collection of bars where Bar.Status equals Foo.Status
                foreach (var bar in this.Bar)
                {
                    if (this.Status.Equals(bar.Status))
                        yield return bar;
                }
            }
        }
    }
}

// Code from this point on is a usage example

class Program
{
    static void Main(string[] args)
    {
        // set up some example data
        var bars = new List<Blarg<SomeStatus>.Bar>();
        bars.Add(new Blarg<SomeStatus>.Bar { Code = "123", Status = SomeStatus.Open });
        bars.Add(new Blarg<SomeStatus>.Bar { Code = "234", Status = SomeStatus.Closed });
        bars.Add(new Blarg<SomeStatus>.Bar { Code = "345", Status = SomeStatus.Funky });
        bars.Add(new Blarg<SomeStatus>.Bar { Code = "456", Status = SomeStatus.Open });
        bars.Add(new Blarg<SomeStatus>.Bar { Code = "567", Status = SomeStatus.Funky });

        // create a Foo object
        Blarg<SomeStatus>.Foo foo = new Blarg<SomeStatus>.Foo
        {
            Bar = bars,
            Status = SomeStatus.Open,
        };

        // now iterate over the Foo.BarsFilteredByStatus property
        // This will iterate over all Bar objects contained within Foo.Bar where Bar.Status equals Foo.Status
        foreach (var bar in foo.BarsFilteredByStatus)
        {
            Console.WriteLine(bar.Code);
        }
    }
}
1 голос
/ 18 октября 2010

Думаю, вы хотите сделать это:

var enumerator = foo.Bar.GetEnumerator();
while (enumerator.MoveNext())
{
    Console.WriteLine(enumerator.Current);
}
1 голос
/ 18 октября 2010

Вы можете перебрать List<T> как есть.

Кроме того - вы должны использовать свойства или авто-свойства для показа List<T> и т. Д. Публичные поля - плохая практика.

Класс:

public class Foo 
{
    private List<Bar> _barList;

    public List<Bar> BarList 
    {
        get
        {
            return this._barList ?? (this._barList = new List<Bar>());
        }
    }
}

Итерация:

Foo myFoo = new Foo();

myFoo.BarList.Add(new Bar());
myFoo.BarList.Add(new Bar());

foreach(Bar bar in myFoo.BarList)
{
    //do something with bar
}
1 голос
/ 18 октября 2010

Вы можете легко перебирать членов Bar, используя foreach. Вам не нужно реализовывать IEnumerable здесь, поскольку List<> уже делает это для вас:

var fooInstance = new Foo();
// initialize...
fooInstance.Bar.Add(new Bar {Code = "a" });
fooInstance.Bar.Add(new Bar {Code = "b" });

// iterate over members of Foo.Bar
foreach( var item in fooInstance.Bar )
{
    // access the proeprties of Bar...
    Console.WriteLine( item.Code );
}  
0 голосов
/ 18 октября 2010

Следующий код работает для меня:

List<Bar> bars = new List<Bar>( );
foreach ( Bar bar in bars ) {
    //Put your code here
}

Вам следует назвать свой экземпляр List, кроме Bar, чтобы избежать путаницы.

...