我有一个List<Email>()
和我的Email
对象看起来像这样:
public class Email
{
public string EmailAddress { get; set; }
public bool IsPrimary { get; set; }
}
当我添加一个设置为主要的新电子邮件地址时,我想将所有其他地址设置为非主要。我目前使用foreach
来处理这个问题。我可以使用LINQ
来处理这个问题吗?
我目前的代码是:
foreach (var item in emails)
{
if(item.EmailAddress.ToLower() != newEmailAddress.ToLower() && item.IsPrimary)
item.IsPrimary = false;
}
Linq查询集合,它不会修改它们。 linq将发挥作用的这个等式中唯一的位置实际上使它成为枚举的一部分 - 过滤你正在迭代的集合而不是在其中执行if
语句。
foreach (var item in emails.Where(e => e.IsPrimary && !e.EmailAddress.Equals(newEmailAddress, StringComparison.InvariantCultureIgnoreCase)))
{
item.IsPrimary = false;
}
编辑:我最初没有包括它,因为它不是LINQ,这就是问题所在,但正如你的问题的评论中提到的List<T>
确实包括ForEach方法。
它看起来像这样:
emails.ForEach(item =>
{
item.IsPrimary = item.IsPrimary && item.EmailAddress.Equals(newEmailAddress, StringComparison.InvariantCultureIgnoreCase);
});
LINQ用于查询而不是修改。话虽如此,有一个List.ForEach
运算符,但大多数时间没有增加可读性。
话虽如此,我个人更喜欢没有副作用导致代码修改集合,但我不反对修改集合中的对象。
在IEnumerable
上添加一个扩展方法来封装foreach
循环:
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
foreach (var s in source)
action(s);
}
然后您可以重新编写代码,如下所示:
emails.Where(item => item.IsPrimary && !item.EmailAddress.Equals(newEmailAddress, StringComparison.InvariantCultureIgnoreCase))
.ForEach(item => item.IsPrimary = false);
(感谢@McAden更好的string
比较,我总是忘记。)
但是,由于您无论如何都要创建竞争条件,如果可行,我建议您撤消操作顺序:
// before adding newEmailAddress
emails[emails.FindIndex(item => item.IsPrimary)].IsPrimary = false; // add error handling if it is possible no `IsPrimary` exists.
// now assign the newEmailAddress and set that item.IsPrimary to true
你可以很容易地做到这一点,但你不应该因为没有人会期望LINQ代码来修改集合中的项目。
emails
.Where(item =>
(item.EmailAddress.ToLower() != newEmailAddress.ToLower() && item.IsPrimary)
.Select(item => { item.IsPrimary = false; return true;})
.All();
请注意,由于LINQ查询实际上是在枚举结果时执行的,因此您需要实际枚举结果的内容。即.All()
电话。
你写这段代码后会发生什么 - 有人(或你一周之内)在最后删除那个愚蠢而毫无意义的.All()
电话,事情会有些不错,但修改不再发生,人们会花一天时间把它整理出来然后用一些词来描述代码的作者。不要去那里。