learner
learner

Reputation: 571

Can code below be rewritten in LINQ/lambda

Can the code below be improved by LINQ or lambda:

foreach (var item in listItem)
{
    var dataRow = dataTable.NewRow();
    foreach (var col in dataTableColumnNames)
    {
        var p = listType.GetProperty(col);
        if (p != null)
        {
            dataRow[col] = p.GetValue(item, null);
        }
    }   
    dataTable.Rows.Add(dataRow);
}

There is nothing wrong though in the program but i wanted to have a feel of LINQ/lambda.

Upvotes: 1

Views: 2327

Answers (4)

Jeff Mercado
Jeff Mercado

Reputation: 134811

As the way you have written, no. Used the right way, you can use some LINQ here, you just need to write your code to facilitate its use. Here, LINQ can be used to gather the data to be added to the table. Then use a loop to add them all.

// let's create the table and its columns
var dataTable = new DataTable("My Table");
dataTable.Columns
         .AddRange(new[] { "Name", "Address" }
                       .Select(n => new DataColumn(n))
                       .ToArray());

// the items to be added
var items = new[]
{
    new { Name = "Bob", Address = "Foo Street" },
    new { Name = "Joe", Address = "Bar Road" },
    new { Name = "Jon", Address = "Baz Avenue" },
};

var itemType = items.GetType().GetElementType();
var rowDatas =
    items.Select(item =>
        from col in dataTable.Columns.Cast<DataColumn>()
        let prop = itemType.GetProperty(col.ColumnName)
        select new
        {
            col.ColumnName,
            Value = prop != null
                ? prop.GetValue(item, null)
                : null,
        });

foreach (var rowData in rowDatas)
{
    var row = dataTable.NewRow();
    foreach (var cell in rowData)
        row[cell.ColumnName] = cell.Value;
}

However you can abuse it and take advantage of the side effects of adding rows to data tables using the Add() method on the table's row collection. You generally shouldn't do this but it does make things more compact.

var itemType = items.GetType().GetElementType();
items.Select(item =>
    dataTable.Rows.Add( // create and add a new row with the following values
        dataTable.Columns
            .Cast<DataColumn>()
            .Select(col => itemType.GetProperty(col.ColumnName))
            .Select(prop => prop != null ? prop.GetValue(item, null) : null)
            .ToArray()
        )
    ).ToList(); // "execute" this thing

Upvotes: 1

mgronber
mgronber

Reputation: 3419

I would get property infos before entering the loop. I assume that the listItem is of type List<T>.

var properties = dataTableColumnNames
        .Select(listItemType.GetProperty)
        .OfType<PropertyInfo>() // drop null values
        .ToList();

listItems.ForEach(item => {
    var dataRow = dataTable.NewRow();
    properties.ForEach(property =>
            dataRow[property.Name] = property.GetValue(item, null));
    dataTable.Rows.Add(dataRow);
});

Upvotes: 0

Avish
Avish

Reputation: 4626

Since your snippet is invoking statements in both its loops (doing assignment in the inner loop and calling Rows.Add() in the outer), this isn't a very good scenario to use LINQ in.

If you still want to write this in a more 'functional' way, the best you can probably do is use a ForEach() extension method instead of the loops, but the code would still end up pretty much the same and would actually not really use LINQ at all.

Trying really hard to use LINQ here, you'd end up with something like this:

listItem
    .Select(item => 
        {
            var dataRow = dataTable.NewRow();
            dataTableColumnNames
               .Select(col => listType.GetProperty(col))
               .Where(p => p != null)
               .ForEach(p => dataRow[p.Name] = p.GetValue(item, null));
            return row;
        })
    .ForEach(row => dataTable.Rows.Add(row));

I'm using the property's p.Name instead of col here to make this simpler, but the general functionality should be the same. As other answers stated, this will not improve readability either.

Note that a ForEach() extension method is not included in plain vanilla LINQ and you'd have to write your own if you don't already have one.

Upvotes: 4

Alessandro
Alessandro

Reputation: 3761

I think you should also consider readability, expecially if your code is likely to change in the future. Your code will not improve much using lamba expressions and will be harder to understand.

Upvotes: 1

Related Questions