diff --git a/src/CsvHelper/CsvDataReader.cs b/src/CsvHelper/CsvDataReader.cs
index a90ec01c4..2572099f7 100644
--- a/src/CsvHelper/CsvDataReader.cs
+++ b/src/CsvHelper/CsvDataReader.cs
@@ -13,12 +13,14 @@ namespace CsvHelper;
///
public class CsvDataReader : IDataReader
{
- private readonly CsvReader csv;
+ private readonly bool leaveOpen;
+ private readonly CsvReader csv;
private readonly DataTable schemaTable;
private bool skipNextRead;
+ private bool disposed;
- ///
- public object this[int i]
+ ///
+ public object this[int i]
{
get
{
@@ -45,7 +47,7 @@ public int Depth
}
///
- public bool IsClosed { get; private set; }
+ public bool IsClosed => disposed;
///
public int RecordsAffected
@@ -65,16 +67,18 @@ public int FieldCount
}
}
- ///
- /// Initializes a new instance of the class.
- ///
- /// The CSV.
- /// The DataTable representing the file schema.
- public CsvDataReader(CsvReader csv, DataTable? schemaTable = null)
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The CSV.
+ /// The DataTable representing the file schema.
+ /// true to leave the open after the object is disposed, otherwise false.
+ public CsvDataReader(CsvReader csv, DataTable? schemaTable = null, bool leaveOpen = false)
{
this.csv = csv;
+ this.leaveOpen = leaveOpen;
- csv.Read();
+ csv.Read();
if (csv.Configuration.HasHeaderRecord && csv.HeaderRecord == null)
{
@@ -94,11 +98,33 @@ public void Close()
Dispose();
}
- ///
+ ///
public void Dispose()
{
- csv.Dispose();
- IsClosed = true;
+ Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Disposes the object.
+ ///
+ /// Indicates if the object is being disposed.
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposed)
+ {
+ return;
+ }
+
+ if (disposing)
+ {
+ if (!leaveOpen)
+ {
+ csv?.Dispose();
+ }
+ }
+
+ disposed = true;
}
///
diff --git a/tests/CsvHelper.Tests/CsvDataReaderDisposalTests.cs b/tests/CsvHelper.Tests/CsvDataReaderDisposalTests.cs
new file mode 100644
index 000000000..fd8ee514b
--- /dev/null
+++ b/tests/CsvHelper.Tests/CsvDataReaderDisposalTests.cs
@@ -0,0 +1,48 @@
+using System.Globalization;
+using System.IO;
+using System.Text;
+using Xunit;
+
+namespace CsvHelper.Tests
+{
+ public class CsvDataReaderDisposalTests
+ {
+ [Fact]
+ public void ShouldNotDisposeCsvReaderWhenLeaveOpenParameterIsTrue()
+ {
+ var s = new StringBuilder();
+ s.AppendLine("StringColumn");
+ s.AppendLine("one");
+ using (var reader = new StringReader(s.ToString()))
+ using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
+ {
+ var dataReader = new CsvDataReader(csv, leaveOpen: true);
+ dataReader.Dispose();
+
+ var record = csv.GetRecord();
+ Assert.NotNull(record);
+ }
+ }
+
+ [Fact]
+ public void DisposeShouldSetIsClosed()
+ {
+ var s = new StringBuilder();
+ s.AppendLine("StringColumn");
+ s.AppendLine("one");
+ using (var reader = new StringReader(s.ToString()))
+ using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
+ {
+ var dataReader = new CsvDataReader(csv, leaveOpen: true);
+ dataReader.Dispose();
+
+ Assert.True(dataReader.IsClosed);
+ }
+ }
+
+ private class TestRecord()
+ {
+ public string StringColumn { get; set; } = string.Empty;
+ }
+ }
+}