0

我正在编写一个小应用程序来修改音频文件的 ID3-Tags。UI 非常简单:您选择您的媒体库,并可以递归地将各种代码逻辑应用于所有文件。

我正在使用 TagLib 在我的项目中读取和写入标签。

为了使用图书馆,我需要阅读所有标签并将它们存储在专辑列表中。

问题:在函数private void GenerateClassifiedLibrary(List files)中抛出了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 以启用大型音乐库的处理。

更新项目:https ://1drv.ms/u/s!AphAKlhyqhP4g2eEk-3aqLeifo89?e=ACkb6w

4

2 回答 2

1

所以这里有错误是关键: Exception: System.InvalidOperationException: Die Sammlung wurde geändert. Der Enumerationsvorgang kann möglicherweise nicht ausgeführt werden.

用英文大致翻译为以下错误信息:

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 语言设置为英语。这将对您有所帮助(因为在 stackoverflow 上有更多可用的资源以及正确的英文翻译)。

于 2020-02-03T21:02:16.677 回答
1

InvalidOperation似乎即将到来,因为您正试图classifiedLibraryforeach循环内进行修改。尝试更新您的foreach查找代码,如下所示:

// using System.Linq;

foreach (Album album in classifiedLibrary.ToList())

这样,您将枚举classifiedLibrary集合的副本(而不是classifiedLibrary其本身),这将允许您将项目添加到classifiedLibrary循环中。

于 2020-02-03T21:07:47.180 回答