Search code examples
c#unity-game-engineautomapperienumerablecsvhelper

Trying to iterate over records from CsvHelper throws ConfigurationException error


I'm trying to iterate through a .csv file to output on the console. I am using CsvHelper and I followed the guides to the T but whenever I try to iterate through the IEnumerable that I get from the GetRecords() method, a ConfigurationException comes up.

Here is the code that I am using

using (var reader_ans = new StreamReader("scriptlists/prac_iden_ans.csv"))
using (var csv_ans = new CsvReader(reader_ans))
{
    var ans = csv_ans.GetRecords<string>();

    foreach (string item in ans)
    {
        Debug.Log(item);
    }
}

It's weird because this is exactly what's in the documentation and multiple websites.

The error that comes up is this:

ConfigurationException: Types that inherit IEnumerable cannot be auto mapped. Did you accidentally call GetRecord or WriteRecord which acts on a single record instead of calling GetRecords or WriteRecords which acts on a list of records?

I was wondering if it's some silly thing that I'm missing because I am pretty new to C#. I am also coding this in Unity3D so could that maybe be part of the problem?

I've tried using the .ToList() method as well on the very first line to no avail.


Edit1:

After trying to create a custom class, I have run into another error, this time from the compiler before I can even run the code.

In essence, in this snippet of code:

foreach (string item in ans)
            {
                Debug.Log(item);
            }

the foreach gets highlighted and it displays an error saying "Cannot convert type 'instructions.ScriptsList' to 'string'". My file is named "instructions.cs".

Some extra information as well that might be the problem:

1) I am writing this piece of code within an IEnumerator, but I don't think that should be a problem as I do have other "foreach" lines in there. Unless CsvHelper uses certain code that would not work while within an IEnumerator?

2) My .csv files were created in excel and they do have headers. It is actually just multiple columns of "Yes" and "No"s. Would creating it in Excel and saving it as .csv (Comma Delimited) have affected how it's being read by CsvHelper?

3) Does it matter that the class is written above this function? (I know this is kind of basic but I'm pretty new to C# and I've noticed that in a lot of the documentation the class is usually written below the function)

Thank you so much for your help!


Solution

  • The error message you received refers to it being unable to populate with the given configuration.

    You want to give GetRecords<> a class or struct which it will populate with the values from each row in your .csv. Your script probably failed due to it trying to populate a row into the string type and failed.

    Example solution, given your .csv looks similar to this:

    Your prac_iden_ans.csv file:

    Path
    C:/example/path/one
    C:/example/path/two
    

    Your .cs C# script file:

    void YourFunction() {
    
        using (var reader_ans = new StreamReader("scriptlists/prac_iden_ans.csv"))
        using (var csv_ans = new CsvReader(reader_ans))
        {
            var ans = csv_ans.GetRecords<ScriptsList>();
    
            foreach (ScriptsList item in ans)
            {
                Debug.Log(item.Path);
            }
        }
    
    }
    
    class ScriptsList {
        public string Path { get; set; }
    }
    

    However, if your .csv file is missing a header row (i.e. the first row specifying what each column represents) you can configure CsvReader to not expect one. However then you have to tell the CsvReader which columns to map to which properties in a different way. One way is the IndexAttribute. Example:

    Your prac_iden_ans.csv file:

    C:/example/path/one
    C:/example/path/two
    

    Your .cs C# script file:

    void YourFunction() {
    
        using (var reader_ans = new StreamReader("scriptlists/prac_iden_ans.csv"))
        using (var csv_ans = new CsvReader(reader_ans))
        {
            csv_ans.Configuration.HasHeaderRecord = false;
            var ans = csv_ans.GetRecords<ScriptsList>();
    
            foreach (ScriptsList item in ans)
            {
                Debug.Log(item.Path);
            }
        }
    
    }
    
    class ScriptsList {
        [Index(0)]
        public string Path { get; set; }
    }
    

    But if your just reading each line in the file row by row I would instead recommend just using a StreamReader, File.OpenRead, or simply File.ReadAllLines. Example:

    Your prac_iden_ans.csv file:

    C:/example/path/one
    C:/example/path/two
    

    Your .cs C# script file:

    string[] ans = File.ReadAllLines("scriptlists/prac_iden_ans.csv");
    
    foreach (string item in ans)
    {
        Debug.Log(item);
    }