-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Open
Labels
Description
Describe the bug
CsvWriter.WriteRecords doesn't call WriteDynamicHeader
To Reproduce
using CsvHelper;
using CsvHelper.Configuration;
using System.Dynamic;
using System.Globalization;
using System.Text;
namespace DynCsv
{
public class DynamicCsvRecord : DynamicObject
{
public string FirstFixedProp { get; set; }
public string SecondFixedProp { get; set; }
public override DynamicMetaObject GetMetaObject(System.Linq.Expressions.Expression parameter)
{
return base.GetMetaObject(parameter);
}
private Dictionary<string, object?> _Dict = new();
public bool TryAdd(string key, object? value) => _Dict.TryAdd(key, value);
public override IEnumerable<string> GetDynamicMemberNames()
{
List<string> names = new();
foreach (var prop in GetType().GetProperties())
{
names.Add(prop.Name);
}
foreach (var key in _Dict.Keys)
{
names.Add(key);
}
return names;
}
public override bool TrySetMember(SetMemberBinder binder, object? value) => _Dict.TryAdd(binder.Name, value);
public override bool TryGetMember(GetMemberBinder binder, out object? result)
{
result = _Dict[binder.Name];
return true;
}
}
public class Program
{
static void Main(string[] args)
{
List<DynamicCsvRecord> records = new();
var rec = new DynamicCsvRecord();
rec.FirstFixedProp = "1st Fixed Value";
rec.SecondFixedProp = "2nd Fixed Value";
rec.TryAdd("FirstDynamicProp", "1st Dynamic Value");
rec.TryAdd("SecondDynamicProp", "2nd Dynamic Value");
records.Add(rec);
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = true,
};
using (var stream = File.Open("Out.csv", FileMode.Create))
using (var writer = new StreamWriter(stream, Encoding.UTF8))
using (var csv = new CsvWriter(writer, config))
{
if (records?.ElementAtOrDefault(0) is IDynamicMetaObjectProvider provider)
{
// unless I explicitly call this method, dynamic column names won't be written
csv.WriteDynamicHeader(provider);
csv.NextRecord();
}
csv.WriteRecords(records);
}
}
}
}
Expected behavior
WriteDynamicHeader should be called from WriteRecords
Screenshots
Additional context
I think the problem is in CsvWriter.cs at line 415-425. At line 425 WriteHeaderFromRecord(enumerator.Current) would call the WriteDynamicHeader(dynamicObject) but at line 415 WriteHeaderFromType<T>() writes the fixed members header and sets hasHeaderBeenWritten true, so WriteDynamicHeader won't be called from WriteHeaderFromRecord