Переменная инициализация в цикле while - PullRequest
5 голосов
/ 13 декабря 2010

У меня есть функция, которая читает файл кусками.

public static DataObject ReadNextFile(){ ...}

И объект данных выглядит так:

public DataObject
{
   public string Category { get; set; }

   // And other members ...
}

В основном я хочу сделать следующее:

List<DataObject> dataObjects = new List<DataObject>();

while(ReadNextFile().Category == "category")
{
   dataObjects.Add(^^^^^ the thingy in the while);
}

Я знаю, что, вероятно, это не так, как это делается.потому что как я могу получить доступ к объекту, который я только что прочитал.

Ответы [ 4 ]

21 голосов
/ 13 декабря 2010

Я думаю, что вы ищете:

List<DataObject> dataObjects = new List<DataObject>();

DataObject nextObject;
while((nextObject = ReadNextFile()).Category == "category")
{
   dataObjects.Add(nextObject);
}

Но я бы не стал этого делать.Я бы написал:

List<DataObject> dataObject = source.ReadItems()
                                    .TakeWhile(x => x.Category == "Category")
                                    .ToList();

, где ReadItems() - это метод, возвращающий IEnumerable<DataObject>, считывающий и выдающий по одному элементу за раз.Возможно, вы захотите реализовать его с помощью блока итератора (yield return и т. Д.).

Предполагается, что вы действительно хотите прекратить чтение, как только найдете первый объект, имеющий другую категорию.Если вы действительно хотите включить все соответствующие DataObject с, измените TakeWhile на Where в приведенном выше запросе LINQ.

(РЕДАКТИРОВАТЬ: С тех пор Саид удалил свои возражения противответ, но я думаю, что я мог бы также оставить пример в стороне ...)

РЕДАКТИРОВАТЬ: Доказательство того, что это будет работать, поскольку Саид, кажется, не верит мне:

using System;
using System.Collections.Generic;

public class DataObject
{
    public string Category { get; set; }
    public int Id { get; set; }
}

class Test
{

    static int count = 0;

    static DataObject ReadNextFile()
    {
        count++;
        return new DataObject
        {
            Category = count <= 5 ? "yes" : "no",
            Id = count
        };
    }

    static void Main()
    {
        List<DataObject> dataObjects = new List<DataObject>();

        DataObject nextObject;
        while((nextObject = ReadNextFile()).Category == "yes")
        {
            dataObjects.Add(nextObject);
        }

        foreach (DataObject x in dataObjects)
        {
            Console.WriteLine("{0}: {1}", x.Id, x.Category);
        }
    }
}

Вывод:

1: yes
2: yes
3: yes
4: yes
5: yes

Другими словами, в списке сохранились ссылки на 5 различных объектов, которые были возвращены из ReadNextFile.

3 голосов
/ 13 декабря 2010

Это субъективно, но я ненавижу этот паттерн (и я полностью осознаю, что я нахожусь в очень маленьком меньшинстве здесь).Вот как я это делаю, когда мне нужно что-то подобное.

var dataObjects = new List<DataObject>();
while(true) {
    DataObject obj = ReadNextFile();
    if(obj.Category != "category") {
        break;
    }
    dataObjects.Add(obj);
}

Но в наши дни лучше сказать

List<DataObject> dataObjects = GetItemsFromFile(path)
                                   .TakeWhile(x => x.Category == "category")
                                   .ToList();

Здесь, конечно, GetItemsFromFile читаетэлементы из файла, на которые указывает path и возвращает IEnumerable<DataObject>.

2 голосов
/ 13 декабря 2010
List<DataObject> dataObjects = new List<DataObject>();
string category = "";

while((category=ReadNextFile().Category) == "category")
{
   dataObjects.Add(new DataObject{Category = category});
}

А если у вас есть более сложный объект, вы можете сделать это (например, Джон):

List<DataObject> dataObjects = new List<DataObject>();
var category = new DataObject();

while((category=ReadNextFile()).Category == "category")
{
   dataObjects.Add(category);
}
0 голосов
/ 13 декабря 2010

Вы должны посмотреть на реализацию IEnumerator в контейнере класса при вызове ReadNextFile (). Тогда у вас всегда будет ссылка на текущий объект с помощью IEnumerator.Current, и MoveNext () вернет искомый бул, который вы ищете для проверки на продвижение. Примерно так:

public class ObjectReader : IEnumerator<DataObject>
{
    public bool MoveNext()
    {
       // try to read next file, return false if you can't
       // if you can, set the Current to the returned DataObject
    }

    public DataObject Current
    {
        get;
        private set;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...