C# Ошибка диагностики InvalidOperationException - PullRequest
0 голосов
/ 03 февраля 2020

Я пишу небольшое приложение для изменения ID3-тегов аудиофайлов. Пользовательский интерфейс очень прост: вы выбираете свою медиатеку и можете рекурсивно применять различные коды логики c ко всем файлам.

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

Чтобы работать с библиотекой, мне нужно прочитать все теги и сохранить их в списке альбомов.

Проблема: В функции private void GenerateClassifiedLibrary (список файлов) является InvalidOperationException выдан, и я не могу найти причину, почему это могло произойти.

Вот исходный код основного приложения :

using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;

namespace Music_Metadata_Experiments
{
    public partial class Form1 : Form
    {
        // Global Variables Declaration
        public static List<Album> classifiedLibrary = new List<Album>();
        // classifiedLibrary is a List of Albums
        // Albums contain Songs
        // Songs contain Tags like "TITLE", "ARTIST", "ALBUM", "GENRE", etc. which can be read and displayed by every Media Player.

        // Start up
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            txtLibraryPath.Text = Environment.GetEnvironmentVariable("USERPROFILE") + "\\Music";
        }

        private void BtnSelectLibrary_Click(object sender, EventArgs e)
        {
            String libraryPath = "";
            List<String> musicFiles;

            if (libraryBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                libraryPath = libraryBrowserDialog.SelectedPath;
            }

            if (libraryPath != null && libraryPath != "")
            {
                txtLibraryPath.Text = libraryPath;
                Log("New Library: " + libraryPath);
            }

            MessageBox.Show("Mediathek wird eingelesen. Dieser Vorgang kann je nach Größe sehr lange dauern.\nDrücke Strg+Shift+Esc für mehr technische Infos.\n\nBitte warten!");

            // Reading the Library:
            musicFiles = GetFilesFromLibrary(libraryPath);
            GenerateClassifiedLibrary(musicFiles);
        }

        // Adjustable Code
        private void ExecuteLogic1_Click(object sender, EventArgs e)
        { // Not implemented yet
            // Goal: Fix this problem -> Song 1 from DISKNUMBER 1 and Song 1 from DISKNUMBER 2 are shown underneath each other, because DISKNUMBER is missing or corrupted.
            // Function: Finds multiple Songs having TITLENUMBER == 1 but are in the same ALBUM and have the same DISKNUMBER or no DISKNUMBER
            Log("Executing Logic 1");

            Log("Library Count: " + classifiedLibrary.Count);
            foreach (Album album in classifiedLibrary)
            {
                Log("Album: " + album.Name);
            }
        }

        private void ExecuteLogic2_Click(object sender, EventArgs e)
        {

        }

        private void ExecuteLogic3_Click(object sender, EventArgs e)
        {

        }

        private void ExecuteLogic4_Click(object sender, EventArgs e)
        {

        }

        private void ExecuteLogic5_Click(object sender, EventArgs e)
        {

        }

        private void ExecuteLogic6_Click(object sender, EventArgs e)
        {

        }

        private void ExecuteLogic7_Click(object sender, EventArgs e)
        {

        }

        private void ExecuteLogic8_Click(object sender, EventArgs e)
        {

        }

        // Helper Methods
        private List<String> GetFilesFromLibrary(string libraryPath)
        {
            String currentFileName = null;
            String fileExtensionToScanFor = "mp3";
            bool skipOnError = true;
            List<String> files = new List<String>();

            try
            {
                foreach (string file in Directory.EnumerateFiles(libraryPath, "*." + fileExtensionToScanFor, SearchOption.AllDirectories))
                {
                    currentFileName = file;
                    files.Add(file);
                }
                Log("Found " + files.Count + " Files in Library");
            }
            catch (Exception any)
            {
                Console.WriteLine("Erroar reading file: " + currentFileName + " // Problem: " + any.Message);

                if (skipOnError == false)
                {
                    Application.Exit();
                }
            }
            return files;
        }

        private void GenerateClassifiedLibrary(List<String> files)
        {
            Log("Generating a Library to work with");
            TagLib.File currentFile = null;

            foreach (string song in files) // ALL Songs found in Library Folder
            {
                try
                {
                    currentFile = TagLib.File.Create(song);

                    String trackAlbum = currentFile.Tag.Album;

                    // Add at least 1 Album to classifiedLibrary
                    if (classifiedLibrary.Count < 1)
                    {
                        List<TagLib.File> albumTrackList = new List<TagLib.File>();
                        albumTrackList.Add(currentFile);
                        Album firstAlbum = new Album(trackAlbum, albumTrackList);

                        classifiedLibrary.Add(firstAlbum);
                    }

                    // Find an Album in classifiedLibrary to which this track belongs to
                    foreach (Album album in classifiedLibrary) // FIXME: InvalidOperationException thrown HERE
                    {
                        Console.WriteLine("Album: " + album.Name);
                        Console.WriteLine("Track: " + currentFile.Tag.Title); // not matching to album above

                        if (album.Name == trackAlbum)
                        {
                            // Album found in classifiedLibrary
                            Log("EXISTING Album: " + trackAlbum + " | Track Count = " + album.Tracks.Count);

                            // Now checking if the track exists or add it
                            List<TagLib.File> tracks = album.Tracks;

                            foreach (TagLib.File track in tracks)
                            {
                                if (track == currentFile)
                                {
                                    // Already added to this Album!
                                    Log("Already added: " + track.Tag.Title);
                                }
                                else
                                {
                                    if (track.Tag.Album == currentFile.Tag.Album)
                                    {
                                        tracks.Add(track);
                                        Log("X Added Track '" + track.Tag.Title + "' to '" + album.Name + "'.");
                                    }
                                    else
                                    {
                                        // Next one.
                                    }
                                    // Next one.
                                }
                                // Next one.
                            }
                            album.Tracks = tracks;
                        }
                        else
                        {
                            // Album not found in classifiedLibrary - FIXME: Album existiert und wird trotzdem neu erstellt
                            Log("NEW Album: " + trackAlbum);

                            List<TagLib.File> trackOrigin = new List<TagLib.File>();
                            Album newAlbum = new Album(trackAlbum, trackOrigin);
                            newAlbum.Tracks.Add(currentFile);
                            Log("Y Added Track '" + currentFile.Tag.Title + "' to '" + newAlbum.Name + "'.");

                            classifiedLibrary.Add(newAlbum);

                            Console.WriteLine("SUCCESS 1");
                        }
                        Console.WriteLine("SUCCESS 2");
                    } // ------------------------------ Exception
                    Console.WriteLine("SUCCESS 3");
                }
                catch (Exception any)
                {
                    Console.WriteLine("------------------------------------------");
                    Console.WriteLine("GenerateClassifiedLibrary: A more fatal Erroar reading file: " + currentFile.Name);
                    Console.WriteLine("Exception: " + any.ToString());
                    Console.WriteLine("------------------------------------------");
                }
            }

            // Generating classifiedLibrary done.
            Log("Generated Library Contents: " + classifiedLibrary.Count + " Albums in classifiedLibrary");
        }

        private void Log(String line)
        {
            RtbLogs.Text += "\n" + line;
        }

    }
}

Здесь источник объекта Album :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Music_Metadata_Experiments
{
    public class Album
    {
        public String Name
        {
            get; set;
        }

        public List<TagLib.File> Tracks
        {
            get; set;
        }

        public Album(String name, List<TagLib.File> tracks)
        {
            Name = name;
            Tracks = tracks;
        }

        public bool Contains(String trackTitle)
        {
            try
            {
                foreach (TagLib.File track in Tracks)
                {
                    if (track.Tag.Title == trackTitle)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("------------------------------------------");
                Console.WriteLine("Exception occured while checking Album.Contains(" + trackTitle + ")");
                Console.WriteLine(e.Message);
                Console.WriteLine("------------------------------------------");
                return false;
            }
            return false;
        }
    }
}

Пример Консольного вывода :

Album: Holz (Weihnachtslied) - Single
Track: Curse My Name
SUCCESS 1
SUCCESS 2
Ausnahme ausgelöst: "System.InvalidOperationException" in mscorlib.dll
------------------------------------------
GenerateClassifiedLibrary: A more fatal Erroar reading file: C:\Users\XXX\Music\iTunes\iTunes Media\Music\Blind Guardian\At the Edge of Time\1-05 Curse My Name.mp3
Exception: System.InvalidOperationException: Die Sammlung wurde geändert. Der Enumerationsvorgang kann möglicherweise nicht ausgeführt werden.
   bei System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
   bei System.Collections.Generic.List`1.Enumerator.MoveNextRare()
   bei System.Collections.Generic.List`1.Enumerator.MoveNext()
   bei Music_Metadata_Experiments.Form1.GenerateClassifiedLibrary(List`1 files) in C:\Users\XXX\Documents\Projekte\Music Metadata Experiments\Music Metadata Experiments\Form1.cs:Zeile 152.
------------------------------------------

Скриншот того, что происходит.

Кстати: я новичок в C#

-

Редактировать: теперь он работает, как и ожидалось. Я также установил для приложения значение x64, чтобы включить обработку больших библиотек Musi c.

Обновленный проект: https://1drv.ms/u/s! AphAKlhyqhP4g2eEk-3aqLeifo89? E = ACkb6w

Ответы [ 2 ]

1 голос
/ 04 февраля 2020

InvalidOperation появляется, потому что вы пытаетесь изменить classifiedLibrary в пределах foreach l oop. Попробуйте обновить код поиска foreach, как показано ниже:

// using System.Linq;

foreach (Album album in classifiedLibrary.ToList())

Таким образом, вы будете перечислять копию коллекции classifiedLibrary (а не самого classifiedLibrary), которая позволит вам добавить элемент до classifiedLibrary в пределах l oop.

1 голос
/ 04 февраля 2020

Таким образом, здесь есть ключевое значение ошибки: Exception: System.InvalidOperationException: Die Sammlung wurde geändert. Der Enumerationsvorgang kann möglicherweise nicht ausgeführt werden.

В английском языке sh примерно переводится в следующее сообщение об ошибке:

System.InvalidOperationException: Collection was modified; enumeration operation may not execute

Это означает, что вы цикл по списку, но вы изменяете этот список (например, добавляя или удаляя элементы), пока вы просматриваете его.

Пример:

var lines = new List<string>();
lines.Add("hello");
lines.Add("world");
foreach(var line in lines) 
{
    lines.Add("adding a new item"); // Invalid operation
}

Недопустимая операция добавления / удаления элемента из списка во время его циклического просмотра.

В ваш случай это виновник:

classifiedLibrary.Add(newAlbum); // << This is not valid inside a loop.
Console.WriteLine("SUCCESS 1");

Как это исправить? Просто - создайте дополнительный список, в который вы добавляете элементы, когда они соответствуют определенным критериям, и не используйте список, по которому вы в данный момент просматриваете.

Другой совет:

Настоятельно советую установить язык windows на engli sh. Это поможет вам (так как в stackoverflow доступно гораздо больше ресурсов с правильным переводом engli sh).

...