使用LINQ将一行变成两个对象?

时间:2013-09-10 12:54:18

标签: c# arrays linq

我有一个项目数组,我将其与更新的项目数组进行比较,以确定更改列的不同列表。它正在发挥作用。

但是我需要在那一行中构建两个对象,因为我需要将两个对象发送到我用来发送电子邮件的API。一个用于旧值,一个用于新值。我尝试过两种不同的方式:

var updates = currentRow.ItemArray
    .Select((o, i) => new { Row = o, Index = i })
    .Where(r => (r.Row == null && updatedRow[r.Index] != null)
            || (r.Row != null && updatedRow[r.Index] != null
            && !r.Row.Equals(updatedRow[r.Index])))
        .Select(r => new AppServices.NotificationData[]
        {
            new AppServices.NotificationData
            {
                Key = string.Format("{0}OldValue",
                    columns[r.Index].ColumnName.EmailTemplateName(type)),
                Value = Convert.ToString(currentRow[r.Index])
            },
            new AppServices.NotificationData
            {
                Key = string.Format("{0}NewValue",
                    columns[r.Index].ColumnName.EmailTemplateName(type)),
                Value = Convert.ToString(updatedRow[r.Index])
            }                        
        });

但实际上,正如预期的那样,这个实际上给了我一个可枚举的数组。我也试过这样:

var updates = currentRow.ItemArray
    .Select((o, i) => new { Row = o, Index = i })
    .Where(r => (r.Row == null && updatedRow[r.Index] != null)
            || (r.Row != null && updatedRow[r.Index] != null
            && !r.Row.Equals(updatedRow[r.Index])))
        .Select(r => new AppServices.NotificationData
        {
            Key = string.Format("{0}OldValue",
                columns[r.Index].ColumnName.EmailTemplateName(type)),
            Value = Convert.ToString(currentRow[r.Index])
        })
        .Select(r => new AppServices.NotificationData
        {
            Key = string.Format("{0}NewValue",
                columns[r.Index].ColumnName.EmailTemplateName(type)),
            Value = Convert.ToString(updatedRow[r.Index])
        });

但问题是第二个Select传递了NotificationData对象中的上一个选择,因此r实际上不是项目数组。

此处currentRowupdatedRow分别是代表新旧数据的DataRow个对象。

我确信有办法让我得到的东西,我只是不知道如何。

那么,我如何获得一个Select,它被构建为返回单个类型,返回同一个对象的两个实例,以便可枚举最终为IEnumerable<NotificationData>

2 个答案:

答案 0 :(得分:6)

在第一个查询中使用SelectMany代替Select

var updates = currentRow.ItemArray
    .Select((o, i) => new { Row = o, Index = i })
    .Where(r => (r.Row == null && updatedRow[r.Index] != null)
            || (r.Row != null && updatedRow[r.Index] != null
            && !r.Row.Equals(updatedRow[r.Index])))
        .SelectMany(r => new AppServices.NotificationData[]
        {
            new AppServices.NotificationData
            {
                Key = string.Format("{0}OldValue",
                    columns[r.Index].ColumnName.EmailTemplateName(type)),
                Value = Convert.ToString(currentRow[r.Index])
            },
            new AppServices.NotificationData
            {
                Key = string.Format("{0}NewValue",
                    columns[r.Index].ColumnName.EmailTemplateName(type)),
                Value = Convert.ToString(updatedRow[r.Index])
            }                        
        });

它会将您的IEnumerable<IEnumerable<T>>展平为IEnumerable<T>

答案 1 :(得分:0)

如果您想要的是每行创建两个对象,然后能够将这两个对象一起发送到您的API,那么我认为最好的方法是使用匿名类型。

var updates = currentRow.ItemArray
    .Select((o, i) => new { Row = o, Index = i })
    .Where(r => (r.Row == null && updatedRow[r.Index] != null)
            || (r.Row != null && updatedRow[r.Index] != null
            && !r.Row.Equals(updatedRow[r.Index])))
        .Select(r => new {
            NotificationForServiceA = new AppServices.NotificationData({
                Key = string.Format("{0}OldValue",
                    columns[r.Index].ColumnName.EmailTemplateName(type)),
                Value = Convert.ToString(currentRow[r.Index])
            }),
            NotificationForServiceB = new AppServices.NotificationData({
                Key = string.Format("{0}NewValue",
                    columns[r.Index].ColumnName.EmailTemplateName(type)),
                Value = Convert.ToString(updatedRow[r.Index])
            })
        });

然后你可以这样使用它:

var oneItem = updates.FirstOrDefault();
myApi(oneItem.NotificationForServiceA, oneItem.NotificationForServiceB);

如果您想要的是每行创建两个NotificationData并将它们合并/展平在一个可枚举的中,那么您应该使用SelectMany来执行该操作。请参阅MarcinJuraszek的答案。