Many solutions are available that convert lists to DataTable
that use reflection, and that would work for converting anonymous types. However, it there are
Improved on @MarcGravell's answer to support:
Nullable types.
static public DataTable ToDataTable(this IList anonymousSource, List keepOrderedFieldsOpt = null)
{
// https://stackoverflow.com/a/13153479/538763 - @MarcGravell
// Added keepOrderedFieldsOpt, nullable types - @crokusek
if (anonymousSource == null) throw new ArgumentNullException();
DataTable table = new DataTable();
if (anonymousSource.Count == 0) return table;
// blatently assume the list is homogeneous
Type itemType = anonymousSource[0].GetType();
table.TableName = itemType.Name;
// Build up orderedColumns
//
List orderedColumns;
if (keepOrderedFieldsOpt != null)
{
Dictionary propertiesByName = itemType.GetProperties()
.ToDictionary(p => p.Name, p => p);
orderedColumns = new List();
List missingFields = null;
foreach (string field in keepOrderedFieldsOpt)
{
PropertyInfo tempPropertyInfo;
if (propertiesByName.TryGetValue(field, out tempPropertyInfo))
orderedColumns.Add(tempPropertyInfo);
else
(missingFields ?? (missingFields = new List())).Add(field);
}
if (missingFields != null)
throw new ArgumentOutOfRangeException("keepOrderedFieldsOpt", "Argument keepOrderedFieldsOpt contains invalid field name(s): " + String.Join(", ", missingFields));
}
else
orderedColumns = itemType.GetProperties().ToList();
List names = new List();
foreach (PropertyInfo prop in orderedColumns)
{
if (prop.CanRead && prop.GetIndexParameters().Length == 0)
{
names.Add(prop.Name);
// Nullable support from stackoverflow.com/a/23233413/538763 - @Damith
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
}
}
names.TrimExcess();
TypeAccessor accessor = TypeAccessor.Create(itemType);
object[] values = new object[names.Count];
foreach (var row in anonymousSource)
{
for (int i = 0; i < values.Length; i++)
values[i] = accessor[row, names[i]];
table.Rows.Add(values);
}
return table;
}