Skip to content

Commit af9d8f8

Browse files
committed
Optimized AddRows, no more dictionary lookup per every item added
1 parent f2484af commit af9d8f8

2 files changed

Lines changed: 44 additions & 7 deletions

File tree

CsvExport/CsvExport.cs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,18 @@ public object this[string field]
130130
_fields.Add(field, num);
131131
}
132132

133-
while (num >= _currentRow.Count) //fill the current row with nulls until we have the right size
134-
_currentRow.Add(null);
135-
136-
_currentRow[num] = value; //set the raw value at position
133+
SetCurrentRowValue(num, value);
137134
}
138135
}
139136

137+
private void SetCurrentRowValue(int num, object value)
138+
{
139+
while (num >= _currentRow.Count) //fill the current row with nulls until we have the right size
140+
_currentRow.Add(null);
141+
142+
_currentRow[num] = value; //set the raw value at position
143+
}
144+
140145
/// <summary>
141146
/// Call this before setting any fields on a row
142147
/// </summary>
@@ -155,12 +160,28 @@ public void AddRows<T>(IEnumerable<T> list)
155160
if (!e.MoveNext()) return; //empty - skip reflection cache warm-up
156161

157162
var accessors = ReflectionCache<T>.Accessors;
163+
164+
// Resolve property names to CSV column indexes once for this batch.
165+
// The row loop below can then write by index instead of doing a dictionary lookup per cell.
166+
var fieldIndexes = new int[accessors.Length];
167+
for (int i = 0; i < accessors.Length; i++)
168+
{
169+
var field = accessors[i].Name;
170+
if (!_fields.TryGetValue(field, out int num))
171+
{
172+
num = _fields.Count;
173+
_fields.Add(field, num);
174+
}
175+
176+
fieldIndexes[i] = num;
177+
}
178+
158179
do
159180
{
160181
AddRow();
161-
foreach (var a in accessors)
182+
for (int i = 0; i < accessors.Length; i++)
162183
{
163-
this[a.Name] = a.Getter(e.Current);
184+
SetCurrentRowValue(fieldIndexes[i], accessors[i].Getter(e.Current));
164185
}
165186
} while (e.MoveNext());
166187
}

UnitTests/UnitTests.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,22 @@ public void TestGeneric()
8282
Assert.IsTrue(csv.Trim() == "sep=,\r\nId,Name\r\n123,Ffff\r\n321,ddd", csv);
8383
}
8484

85+
[TestMethod]
86+
public void TestGenericAfterExistingColumn()
87+
{
88+
List<MyClass> list = new() { new MyClass { Id = 123, Name = "Ffff" } };
89+
90+
var myExport = new CsvExport();
91+
myExport.AddRow();
92+
myExport["Prefix"] = "manual";
93+
94+
myExport.AddRows(list);
95+
96+
string csv = myExport.Export();
97+
98+
Assert.IsTrue(csv.Trim() == "sep=,\r\nPrefix,Id,Name\r\nmanual\r\n,123,Ffff", csv);
99+
}
100+
85101
[TestMethod]
86102
public void TestEmpty()
87103
{
@@ -389,4 +405,4 @@ public class MyClass
389405
public int Id { get; set; }
390406
public string Name { get; set; } = string.Empty;
391407
}
392-
}
408+
}

0 commit comments

Comments
 (0)