Можно ли переписать приведенный ниже код в LINQ / lambda? - PullRequest
1 голос
/ 07 апреля 2011

Может ли приведенный ниже код быть улучшен с помощью LINQ или 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);
}

В программе нет ничего плохого, но я хотел почувствовать LINQ / lambda.

Ответы [ 4 ]

4 голосов
/ 07 апреля 2011

Поскольку ваш фрагмент вызывает операторы в обоих его циклах (выполнение присваивания во внутреннем цикле и вызов Rows.Add () во внешнем), это не очень хороший сценарий для использования LINQ в.

Если вы все еще хотите написать это более «функциональным» способом, лучшее, что вы, вероятно, можете сделать, это использовать метод расширения ForEach () вместо циклов, но код все равно в конечном итоге будет таким же и будет на самом деле не совсем использовать LINQ вообще.

Стараясь изо всех сил использовать LINQ здесь, вы получите что-то вроде этого:

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));

Я использую свойство p.Name вместо col, чтобы упростить эту задачу, но общая функциональность должна быть такой же. Как отмечалось в других ответах, это также не улучшит читабельность.

Обратите внимание, что метод расширения ForEach () не включен в простой ванильный LINQ, и вам придется написать свой собственный, если у вас его еще нет.

1 голос
/ 07 апреля 2011

Как вы написали, нет. При правильном использовании вы можете использовать некоторые LINQ здесь, вам просто нужно написать свой код, чтобы облегчить его использование. Здесь LINQ можно использовать для сбора данных, которые будут добавлены в таблицу. Затем используйте цикл, чтобы добавить их все.

// 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;
}

Однако вы можете злоупотребить этим и воспользоваться побочными эффектами добавления строк в таблицы данных с помощью метода Add() в коллекции строк таблицы. Как правило, вы не должны этого делать, но это делает вещи более компактными.

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
1 голос
/ 07 апреля 2011

Я думаю, вы должны также рассмотреть удобочитаемость, особенно если ваш код может измениться в будущем.Ваш код не сильно улучшится при использовании выражений lamba, и его будет сложнее понять.

0 голосов
/ 07 апреля 2011

Я бы получил информацию о свойствах перед входом в цикл.Я предполагаю, что listItem имеет тип 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);
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...