如何在LINQ投影中仅修改一个或两个字段?

6

我有这个LINQ查询:

List<Customers> customers = customerManager.GetCustomers();

return customers.Select(i => new Customer {
    FullName = i.FullName,
    Birthday = i.Birthday, 
    Score = i.Score,
    // Here, I've got more fields to fill
    IsVip = DetermineVip(i.Score)
}).ToList();

换句话说,在我的业务方法中,我只想根据条件修改客户列表中的一个或两个字段。我有两种方法可以做到这一点:
1.使用`for...each`循环遍历客户并修改该字段(命令式方法)。
2.使用LINQ投影(声明式方法)。
是否有任何技术可以在LINQ查询中使用,仅修改投影中的一个属性?例如,类似于:
return customers.Select(i => new Customer {
    result = i // telling LINQ to fill other properties as it is
    IsVip = DetermineVip(i.Score) // then modifying this one property
}).ToList();
5个回答

6

您可以使用

return customers.Select(i => {
    i.IsVip = DetermineVip(i.Score);
    return i;
}).ToList();

关于这样做的一个注意事项是你必须要小心一点。例如,如果你执行 customer.FullName += "foo" 并且你最终枚举了两次集合,你会得到一些非常有趣的结果。 - lc.

2
与其他答案相反,您可以通过在Select语句中调用一个方法来修改linq中的源内容(请注意,虽然EF不支持此操作,但这对您不应该是一个问题)。
return customers.Select(customer => 
{
    customer.FullName = "foo";
    return customer;
});

不确定,但我也得到了一个。但是做这件事情需要小心一点。例如,如果您执行 customer.FullName += "foo" 并且您最终枚举集合两次,那么您将得到一些非常有趣的结果。 - lc.
lc。也许你把“customer”误认为是“customers”。所提供的解决方案只会迭代一次集合。 - Polity

2

如果您创建一个复制构造函数,它可以使用现有对象的值来初始化一个新对象:

partial class Customer
{
    public Customer(Customer original)
    {
        this.FullName = original.FullName;
        //...
    }
}

那么你可以这样做:

return customers.Select(i => new Customer(i) { IsVip = DetermineVip(i.Score)})
    .ToList()

但是这样做的缺点是,您将基于每个现有对象创建一个新的“客户”对象,而不是修改现有对象 - 这就是为什么我在引号中放置了“可以”的原因。我不知道这是否真正符合您的要求。

1
不,Linq旨在遍历集合而不影响源可枚举对象的内容。
但是,您可以创建自己的方法来迭代和更改集合:
public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
    foreach(T item in enumeration)
    {
        action(item);
    }
}

您可以按如下方式使用:
return customers.ToList()
                .ForEach(i => i.IsVip = DetermineVip(i.Score))
                .ToList();

请注意,第一个 ForEach 将克隆源列表。

0

由于客户已经是一个列表,您可以使用ForEach方法:

customers.ForEach(c => c.IsVip = DetermineVip(c.Score));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接