List of classes to datatable I'm looking for a function to take a list of generic classes, and map it to different layout of datatable.

That means, I can't just directly map my class property names and values to grid, I need to convert it to the new values.

The solution that I came up with works, but it feels ... sloppy. Can anyone recommend a better way of doing it?

class Program
{
    static void Main(string[] args)
    {
        var list = new List&lt;InputClass&gt;()
        {
            new InputClass {SomeField = "A", OtherField = 1},
            new InputClass {SomeField = "B", OtherField = 2},
            new InputClass {SomeField = "C", OtherField = 3},
            new InputClass {SomeField = "D", OtherField = 4}
        };

        var dict = new Dictionary&lt;string, Func&lt;InputClass, object&gt;&gt;()
        {
            {"ColA", (f) =&gt; $"{f.SomeField}ABCD"},
            {"ColB", (f) =&gt; DateTime.Now}
        };

        var dt = ToDataTable(list, dict);
        Console.ReadKey();
    }

    public static DataTable ToDataTable&lt;T&gt;(List&lt;T&gt; list, Dictionary&lt;string, Func&lt;T, object&gt;&gt; columns) where T : class 
    {
        var dt = new DataTable();

        foreach (var key in columns.Keys)
        {
            var func = columns[key];
            Type[] funcParams = (func.GetType()).GenericTypeArguments;
            dt.Columns.Add(key, funcParams[1]);
        }

        foreach (var record in list)
        {
            var objects = new List&lt;object&gt;();
            foreach (var key in columns.Keys)
            {
                objects.Add(columns[key](record));
            }

            dt.Rows.Add(objects.ToArray());
        }

        return dt;
    }
}

class InputClass
{
    public string SomeField { get; set; }

    public int OtherField { get; set; }
}
Cases like this I would hide the "sloppy" 

I would create a class that holds the mappings from the class to the table and create methods to build the mappings.  This way there is no need for reflection and we can save the funcs to be reused. 

public class Mapper&lt;TSource&gt;
{
    private readonly DataTable _source = new DataTable();
    private readonly List&lt;Func&lt;TSource, object&gt;&gt; _mappings = new List&lt;Func&lt;TSource, object&gt;&gt;();

    public Mapper&lt;TSource&gt; Configure&lt;TProperty, TData&gt;(Func&lt;TSource, TProperty&gt; property, string colName,
        Func&lt;TProperty, TData&gt; mapper)
    {
        _source.Columns.Add(colName, typeof (TData));
        Func&lt;TSource, object&gt; map = s =&gt; mapper(property(s));
        _mappings.Add(map);
        return this;
    }

    public Mapper&lt;TSource&gt; Configure&lt;TProperty&gt;(Func&lt;TSource, TProperty&gt; property, string colName)
    {
        _source.Columns.Add(colName, typeof(TProperty));
        Func&lt;TSource, object&gt; map = s =&gt; property(s);
        _mappings.Add(map);
        return this;
    }

    public Mapper&lt;TSource&gt; Configure&lt;TData&gt;(string colName, Func&lt;TData&gt; mapper)
    {
        _source.Columns.Add(colName, typeof(TData));
        Func&lt;TSource, object&gt; map = _ =&gt; mapper();
        _mappings.Add(map);
        return this;
    }

}


With this class we now have a datatable in _source that holds the columns that we want and a list of mappings from our source to the datatable.   Now we just need to create a ToDataTable method to use these in the same class.

public DataTable ToDataTable(IEnumerable&lt;TSource&gt; items)
{
    // make a new datatable with the same columns as the source
    var dt = _source.Clone();

    foreach (var item in items)
    {
        dt.Rows.Add(_mappings.Select(f =&gt; f(item)).ToArray());
    }

    return dt;
}


We would use it like so.  Typically you would only do the configurations once and then just reuse it with different lists. 

var inputClassMapper = new Mapper&lt;InputClass&gt;();
inputClassMapper.Configure(f =&gt; f.SomeField, "ColA", s =&gt; $"{s}ABCD")
                .Configure("ColB", () =&gt; DateTime.Now);

// have mapper convert input to datatables
var dt = inputClassMapper.ToDataTable(list);