2016-04-07 2 views
3

Интересная проблема с IEnumerable и Linq.Множественное перечисление IEnumerable - StackOverflowException

static void Main(string[] args) 
{ 
    var subject = "#Accountancy #premier #Agile #Apache #automation #Automation #banking #Banking #bankIngs #AutoMation"; 
    var hashtags = subject.Split('#').Select(hashtag => hashtag.Trim().ToUpper()).Distinct(); 

    var plurals = hashtags.Where((hashtag) => 
    { 
     return hashtags.Contains($"{hashtag.ToUpper()}S"); 
    }).Select(h => $"{h.ToUpper()}S");  //.ToList(); (1) - will not break 

    //filter hashtags 
    hashtags = hashtags.Except(plurals); //.ToList(); (2) - will not break 

    //if iterate, would break with: 
    //System.StackOverflowException was unhandled Message: An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll 
    foreach (var hashtag in hashtags) 
    { 
     Console.WriteLine(hashtag); 
    } 

    Console.Read(); 
} 

Любопытно, как объяснить, почему происходит исключение переполнения?

+0

Используйте новую переменную в фильтре, чтобы избежать изменения 'hashtags' до полной итерации по ней. – wimh

+1

Читайте о ** Linq и отложенном исполнении ** и объедините эти показания с двумя другими ответами. Затем вы увидите, почему ваш код ломается. Отсроченное исполнение может привести к некоторым ловушкам. – derpirscher

ответ

4

Пройдитесь по ней шаг за шагом.

  1. Множественное является каждое слово в хэштегов который также имеет то же самое слово, заканчивающееся в с
  2. Hashtags является каждое слово, кроме существительных.

Для выполнения 2 необходимо выполнить 1. Однако, Хештеги постоянно меняется, поэтому множественном пытается выполнить не на оригинальной коллекции, но на результат 2 (что опять-таки, опирается на результат 1).

Ваш запрос будет пытаться быть:

hashtags = hashtags.Except(plurals); 

Замена plurals

hashtags = hashtags.Except(
      hashtags.Where(hashtag => { return hashtags.Contains($"{hashtag.ToUpper()}S"); }) 
        .Select(h => $"{h.ToUpper()}S") 
      ); 

Но hashtags является hashtags.Except(plurals);

hashtags.Except(
      hashtags.Except(plurals).Where(hashtag => { return hashtags.Contains($"{hashtag.ToUpper()}S"); }) 
        .Select(h => $"{h.ToUpper()}S") 
      ); 

И тогда нам нужно снова заменить plurals .. и так на.

Ваши исправления (добавление .ToList()) - это логичный способ его исправить.

3

Вы повторно назначаете хэштеги (которые не были оценены) на другую оценку, которая приводит к бесконечному циклу. Если вы поместите вторую оценку в другую переменную, она будет работать:

var hashtags2 = hashtags.Except(plurals); 

foreach (var hashtag in hashtags2) 
{ 
    Console.WriteLine(hashtag); 
} 
+1

Я не думаю, что это полный ответ - hashtags = hashtags.Except (hashtags.Where (h => h.StartsWith ("B"))); 'не выбрасывает исключение переполнения стека. – stuartd

Смежные вопросы