Список для каждого перерыва - PullRequest
16 голосов
/ 30 июня 2010

есть ли способ выйти из метода расширения foreach? Ключевое слово "break" не распознает метод расширения как допустимую область, из которой нужно выйти.

//Doesn't compile
Enumerable.Range(0, 10).ToList().ForEach(i => { System.Windows.MessageBox.Show(i.ToString()); if (i > 2)break; });

Редактировать: удалено "linq" из вопроса


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

Ответы [ 8 ]

17 голосов
/ 30 июня 2010

Вероятно, правильнее назвать это List<T> Foreach против LINQ.

В любом случае, хотя нет, нет способа выйти из этого цикла. Прежде всего потому, что на самом деле это не цикл. Это метод, который принимает делегат, который вызывается внутри цикла.

Создание ForEach с возможностью разрыва довольно просто, хотя

public delegate void ForEachAction<T>(T value, ref bool doBreak);
public static void ForEach<T>(this IEnumerable<T> enumerable, ForEachAction<T> action) {
    var doBreak = false;
    foreach (var cur in enumerable) {
        action(cur, ref doBreak);
        if (doBreak) {
            break;
        }
    }
}

Затем вы можете переписать свой код следующим образом

Enumerable.Range(0,10)
    .ForEach((int i,ref bool doBreak) => {
        System.Windows.MessageBox.Show(i.ToString()); 
        if ( i > 2) {doBreak = true;}
    });
11 голосов
/ 30 июня 2010

Я рекомендую использовать TakeWhile .

Enumerable.Range(0, 10).TakeWhile(i => i <= 2).ToList().ForEach(i => MessageBox.Show(i.ToString()));

Или, используя Rx :

Enumerable.Range(0, 10).TakeWhile(i => i <= 2).Run(i => MessageBox.Show(i.ToString()));
3 голосов
/ 30 июня 2010

Почему бы не использовать Where?

Enumerable.Range(0, 10).Where(i => i <= 2).ToList().ForEach(...)
1 голос
/ 20 декабря 2014

Попробуйте выражение "return" вместо "break"; это функция делегата, а не реальный цикл.

Попытка:

Enumerable.Range(0, 10).ToList().ForEach(i => { System.Windows.MessageBox.Show(i.ToString()); if (i > 2) return; });
0 голосов
/ 28 июня 2017

У меня есть случай, когда мне нужно зациклить действия, пока условие не станет ложным, и каждое действие может изменить значение, используемое для отслеживания условия. Я придумал этот вариант .TakeWhile (). Преимущество здесь состоит в том, что каждый элемент в списке может участвовать в некоторой логике, тогда цикл может быть прерван при условии, не имеющем прямого отношения к элементу.

new List<Action> {
    Func1,
    Func2
}.TakeWhile(action => {
    action();
    return _canContinue;
});
0 голосов
/ 20 июня 2017

Почему бы не throw new Exception("Specific message") или не использовать логический флаг?

DataTable dt = new DataTable();
bool error = false;

try
{
    dt.AsEnumerable().ToList().ForEach(dr =>
    {
        if (dr["Col1"].ToString() == "")
        {
            error = true;
            throw new Exception("Specific message");
        }
        else 
            // Do something
    });
}
catch (Exception ex)
{
    if (ex.Message == "Specific message" || error) 
        // do something
    else
        throw ex;
}
0 голосов
/ 19 апреля 2017

Для себя я использовал Linq Select + FirstOrDefault.Преобразуйте «каждого» в списке, но, поскольку мы просим Первое, оно прекратит преобразовывать их после нахождения первого, соответствующего.Option и мой метод AsThingOption могут преуспеть в преобразовании, и когда это произойдет, мы перестанем перебирать список.Если условия внутри метода AsThingOption никогда не преуспевают в преобразовании, тогда конечным результатом является None.

Надеюсь, это поможет!

0 голосов
/ 25 января 2013

Почему бы не использовать foreach?...

PS: Шучу, и, как вы упомянули, я понимаю идею попытаться понять, как это сделать с помощью Linq (и гуглил здесь по той же причине) ... теперь по причинам обслуживания / готовностив производственном коде угадайте, что простой foreach иногда достаточно хорош.

...