@JoshClose
private IEnumerable<Participant> ReadCSV(string path)
{
IEnumerable<Participant> records = null;
using (var sr = new StreamReader(path))
{
var reader = new CsvReader(sr);
reader.Configuration.HasHeaderRecord = false;
reader.Read();
records = reader.GetRecords<Participant>();
sr.Close();
}
return records;
}
when the csv reader arrived at end of the line of csv, an error appears like this:
System.NullReferenceException: Object reference not set to an instance of an object.
at CsvHelper.CsvReader.<GetRecords>d__63`1.MoveNext()
at Reader.testForm..ctor(IEnumerable`1 peserta) in C:\Users\SIGI-PC\Documents\Visual Studio 2015\Projects\Reader\Reader\testForm.cs:line 28
Exception thrown: 'System.NullReferenceException' in Reader.exe
You're closing the stream before you've read the records. GetRecords<T> returns an IEnumerable<T> that will yield records. What that means is it doesn't actually pull the records until you access them. If you're returning the IEnumerable<T>, you can't close the reader because it needs to be used to get the records.
Take a look at how yield works. https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/yield
@JoshClose, you should change the code sample in the getting started page where it says:
C#
using (var reader = new StreamReader("path\\to\\file.csv"))
using (var csv = new CsvReader(reader))
{
var records = csv.GetRecords<Foo>();
}
This won't work when using records outside of the using blocks. I just did that same mistake.
What should I add to the sample? This is fundamentals of how a using block works. Should I add a blurb about that in the text below the example?
C#
using (var reader = new StreamReader("path\\to\\file.csv"))
using (var csv = new CsvReader(reader))
{
foreach (var record in csv.GetRecords<Foo>())
{
// do something with record
}
}
@FObermaier I think @JoshClose 's intention was to imply that by putting the declaration var = records _inside_ the using. By declaring it there, the variable records cannot be used outside the using scope anyway (regardless whether it is using yield or not)
C#
List<Foo> list = new List<Foo>();
using (var reader = new StreamReader(fileName))
{
var csv = new CsvReader(reader,CultureInfo.InvariantCulture);
while (csv.Read())
{
var item = csv.GetRecord<Foo>();
list.Add(item);
}
return list;
}
Like this ,It is OK!
List<Foo> list = new List<Foo>(); using (var reader = new StreamReader(fileName)) { var csv = new CsvReader(reader,CultureInfo.InvariantCulture); while (csv.Read()) { var item = csv.GetRecord<Foo>(); list.Add(item); } return list; }Like this ,It is OK!
ToList() if all you need is to execute the query immediately and return a List (with C# 8 simplified using syntax).
using var reader = new StreamReader(filePath);
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
return csv.GetRecords<Foo>().ToList();
Most helpful comment
You're closing the stream before you've read the records.
GetRecords<T>returns anIEnumerable<T>that willyieldrecords. What that means is it doesn't actually pull the records until you access them. If you're returning theIEnumerable<T>, you can't close the reader because it needs to be used to get the records.