2014-10-03 3 views
-4

Для того, чтобы упростить код, чтобы я мог лучше понять, я пытаюсь преобразовать эту рекурсии вызов в время цикла:Как переписать этот рекурсивный вызов как цикл?

function getMusic(IStorageFolder folder) { 
    int cnt = 0; 
    var folders = await folder.GetFoldersAsync(); 
    if (folders != null) 
     foreach (var fol in folders) 
      await getMusic(fol); 

    var files = await folder.GetFilesAsync(); 
    foreach (var file in files) 
    { 
     MusicProperties musicProperties = await file.Properties.GetMusicPropertiesAsync(); 
     source.Add(new Music("artist", "title", "album"); 
     cnt++; 
    } 
} 

В коде source является ObservableCollection типа Music (содержит три параметра, как видна в source.Add... линия).

Однако, я не увенчался успехом. Вот моя попытка, которая, похоже, не заполняет список source.

private async Task getMusic(IStorageFolder folder) 
{ 
    Stack<StorageFolder> fold = new Stack<StorageFolder>(); 
    int count = 0; int firstTen = 0; 
    var folders = await folder.GetFoldersAsync(); 

    foreach (var indvFolder in folders) 
     fold.Push(indvFolder); 

    while (count < fold.Count) 
    { 
     var fol = fold.Pop(); 
     if (firstTen > 9) 
      break; 
     var files = await fol.GetFilesAsync(); 
     foreach (var file in files) 
     { 
      MusicProperties musicProperties = await file.Properties.GetMusicPropertiesAsync(); 
      source.Add(new Music("artist", "title", "album")); 
      count++; 
     } 
     firstTen++; 
    } 
} 
+0

у вас был успешным в «Отладке» кода. Неужели вы не можете понять цикл foreach ..? – MethodMan

+0

У меня была «Debug.WriteLine» после каждой строки в коде для проверки значений переменных. Я взял их из этого кода, чтобы он был чистым. – DemCodeLines

+0

Итак, в чем проблема/проблема, знаете ли вы, как использовать Quick Watch отладчика – MethodMan

ответ

0

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

Обход файловой системы для получения всех файлов - это операция, с которой вы уже почти справились. На самом деле, так как дерева, как это будут перемещаться так же, как все время, вы можете даже обобщить асинхронный обход дерева в структурно-независимом алгоритм:

public static async Task<IEnumerable<T>> TraverseAsync<T>(
    this IEnumerable<T> source 
    , Func<T, Task<IEnumerable<T>>> childrenSelector) 
{ 
    var queue = new Queue<T>(source); 
    List<T> results = new List<T>(); 
    while (queue.Any()) 
    { 
     var next = queue.Dequeue(); 
     results.Add(next); 
     foreach (var child in await childrenSelector(next)) 
      queue.Enqueue(child); 
    } 
    return results; 
} 

Используя это теперь вы можете взять начальную папку , пересекают график, чтобы получить все папки, сопоставить эти папки все файлы, а затем сопоставить эти файлы на все их свойства:

private async Task<IEnumerable<Music>> getMusic(IStorageFolder rootFolder) 
{ 
    var folders = await new[] { rootFolder } 
     .TraverseAsync(folder => folder.GetFoldersAsync()); 
    var files = (await Task.WhenAll(
     folders.Select(folder => folder.GetFilesAsync()))) 
     .SelectMany(folder => folder); 
    var properties = (await Task.WhenAll(
     files.Select(file => file.GetMusicPropertiesAsync()))) 
     .SelectMany(property => property); 
    return properties.Select(prop => new Music()); 
} 

Это сделано немного грязнее из-за необходимости держать все асинхронные , Если сначала сделать асинхронную версию SelectMany:

public static async Task<IEnumerable<TResult>> SelectManyAsync<TSource, TResult>(
    this Task<IEnumerable<TSource>> source, 
    Func<TSource, Task<IEnumerable<TResult>>> resultSelector) 
{ 
    var sourceSequence = await source; 
    var sequences = await Task.WhenAll(sourceSequence.Select(resultSelector)); 
    return sequences.SelectMany(x => x); 
} 

Это упрощает код:

private async Task<IEnumerable<Music>> getMusic(IStorageFolder rootFolder) 
{ 
    var properties = await new[] { rootFolder } 
     .TraverseAsync(folder => folder.GetFoldersAsync()) 
     .SelectManyAsync(folder => folder.GetFilesAsync()) 
     .SelectManyAsync(file => file.GetMusicPropertiesAsync()); 
    return properties.Select(prop => new Music()); 
} 

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

2

fold.Pop() изменяется fold.Count. fold.Count не будет включать уже обработанные элементы, поэтому count < fold.Count не имеет смысла.

Вместо этого используйте while (fold.Count > 0)

Кроме того, этот материал должен быть внутри цикла, так как исходный код посетил подкаталоги подкаталогов:

foreach (var indvFolder in fol.GetFoldersAsync()) 
    fold.Push(indvFolder); 

Установка является просто

fold.Push(folder); 
Смежные вопросы