用LINQ替换嵌套的foreach;修改和更新深度内的属性
考虑对更改的要求,该数据成员是深度为5或6级的对象的一个或多个属性。用LINQ替换嵌套的foreach;修改和更新深度内的属性
有些子集需要迭代才能到达需要检查&修改的属性。
这里我们调用一个清除员工街道地址的方法。由于我们在循环中不断变化的数据,目前的实现需要一个for
循环,防止异常:
不能分配给“someVariable”,因为它是一个“的foreach迭代变量”
这里的当前算法(混淆)嵌套foreach
和for
。
foreach (var emp in company.internalData.Emps) {
foreach (var addr in emp.privateData.Addresses)
{
int numberAddresses = addr.Items.Length;
for (int i = 0; i < numberAddresses; i++)
{
//transform this street address via a static method
if (addr.Items[i].Type =="StreetAddress")
addr.Items[i].Text = CleanStreetAddressLine(addr.Items[i].Text);
}
}
}
问: 可以此算法使用LINQ重新实现?要求是原始集合通过该静态方法调用更改其数据。
更新:我在想/倾向于jQuery /选择器类型的解决方案。我没有那样具体地说这个问题。我意识到我对这个想法过于深刻(没有副作用)。谢谢大家!如果有这种方法来执行类似jQuery的选择器,请让我们看看它!
回答:
LINQ不打算修改对象的集合。您不希望SELECT sql语句修改所选行的值,对吗?它有助于记住LINQ代表什么 - Language Integrated Natural 查询。在linq查询中修改对象,恕我直言,反模式。
Stan R.的回答是使用foreach循环的更好解决方案,我想。
回答:
foreach(var item in company.internalData.Emps .SelectMany(emp => emp.privateData.Addresses)
.SelectMany(addr => addr.Items)
.Where(addr => addr.Type == "StreetAddress"))
item.Text = CleanStreetAddressLine(item.Text);
回答:
LINQ不提供副作用的选项。但是你可以做:
company.internalData.Emps.SelectMany(emp => emp.Addresses).SelectMany(addr => Addr.Items).ToList().ForEach(/*either make an anonymous method or refactor your side effect code out to a method on its own*/);
回答:
var dirtyAddresses = company.internalData.Emps.SelectMany(x => x.privateData.Addresses) .SelectMany(y => y.Items)
.Where(z => z.Type == "StreetAddress");
foreach(var addr in dirtyAddresses)
addr.Text = CleanStreetAddressLine(addr.Text);
回答:
你可以做到这一点,但你并不是真的想。几位博主谈到了Linq的功能性,如果你看看所有MS提供的Linq方法,你会发现它们不会产生副作用。它们会产生返回值,但它们不会改变其他任何东西。通过Linq ForEach方法搜索参数,您将很好地解释这个概念。
考虑到这一点,你probaly想要的东西是这样的:
var addressItems = company.internalData.Emps.SelectMany( emp => emp.privateData.Addresses.SelectMany(
addr => addr.Items
)
);
foreach (var item in addressItems)
{
...
}
但是,如果你想你问什么,那么这就是你需要去的方向:
var addressItems = company.internalData.Emps.SelectMany( emp => emp.privateData.Addresses.SelectMany(
addr => addr.Items.Select(item =>
{
// Do the stuff
return item;
})
)
);
回答:
I don't like mixing "query comprehension" syntax and dotted-method-call syntax在相同的声明。
我确实喜欢将查询与动作分开。它们在语义上是不同的,因此在代码中分离它们通常是有意义的。
var addrItemQuery = from emp in company.internalData.Emps from addr in emp.privateData.Addresses
from addrItem in addr.Items
where addrItem.Type == "StreetAddress"
select addrItem;
foreach (var addrItem in addrItemQuery)
{
addrItem.Text = CleanStreetAddressLine(addrItem.Text);
}
有关代码的几个风格说明;这些都是个人的,所以我可能会不同意:
- 一般情况下,我尽量避免缩写(
Emps
,emp
,addr
) - 名称不一致是更加令人困惑(
addr
与Addresses
):选择一个与坚持它 - “数字”这个词是含糊不清的。它可以是一个身份(“犯人号码378请前进”)或计数(“该场的羊数为12”)。由于我们在代码中大量使用这两个概念,因此清楚这一点很有价值。我经常使用第一个“索引”和第二个“计数”。
- 拥有
type
字段的字符串是一种代码异味。如果你能使它成为一个enum
你的代码可能会更好。
回答:
肮脏的单线。
company.internalData.Emps.SelectMany(x => x.privateData.Addresses) .SelectMany(x => x.Items)
.Where(x => x.Type == "StreetAddress")
.Select(x => { x.Text = CleanStreetAddressLine(x.Text); return x; });
回答:
要使用foreach循环,我首先创建当地的“列表”变量更新LINQ的结果,然后使用foreach循环执行更新。值以这种方式更新。在这里阅读更多:
How to update value of LINQ results using FOREACH loop
以上是 用LINQ替换嵌套的foreach;修改和更新深度内的属性 的全部内容, 来源链接: utcz.com/qa/257953.html