我有一个Foreach声明,如下所示
foreach (var fieldMappingOption in collectionHelper.FieldMappingOptions
.Where(fmo => fmo.IsRequired && !fmo.IsCalculated
&& !fmo.FieldDefinition.Equals( MMPConstants.FieldDefinitions.FieldValue)
&& (implicitParents || anyParentMappings
|| fmo.ContainerType == collectionHelper.SelectedOption.ContainerType)))
{
if (!collectionHelper.FieldMappingHelpers
.Any(fmh => fmh.SelectedOption.Equals(fieldMappingOption)))
{
requiredMissing = true;
var message = String.Format(
"The MMP column {0} is required and therefore must be mapped to a {1} column.",
fieldMappingOption.Label, session.ImportSource.CollectionLabel);
session.ErrorMessages.Add(message);
}
}
我可以将上述复杂的foreach和IF语句分解为更好的格式化LINQ表达式。此外,性能明智会更好。请建议。
答案 0 :(得分:1)
重新:将Foreach更改为Linq语句
好吧,您可以将两个for循环转换为LINQ Select,并且由于在循环内部,您只有一个具有附加谓词的分支,您可以将谓词组合到外部循环中,如下所示:
var missingFieldMappingOptions = collectionHelper.FieldMappingOptions
.Where(fmo => fmo.IsRequired && !fmo.IsCalculated
&& !fmo.FieldDefinition.Equals( MMPConstants.FieldDefinitions.FieldValue)
&& (implicitParents || anyParentMappings
|| fmo.ContainerType == collectionHelper.SelectedOption.ContainerType))
&& !collectionHelper.FieldMappingHelpers
.Any(fmh => fmh.SelectedOption.Equals(fmo)))
.Select(fmo =>
$"The MMP column {fmo.Label} is required and therefore" +
$" must be mapped to a {session.ImportSource.CollectionLabel} column.");
var requiredMissing = missingFieldMappingOptions.Any();
session.ErrorMessages.AddRange(missingFieldMappingOptions)
然而,即使LINQ也不能使.Where
中的过滤条款消失,因此LINQ Select几乎不比for循环更具可读性,并且实际上也不具备任何性能(设置requiredMissing
标志并在一个批量块中添加session.ErrorMessages
可能会带来一些边际好处。
<强>性能强>
从性能角度来看,下面是有问题的,因为在外部for循环中合并时会O(N log N)
(幸运的是,如果找到匹配,.Any()
会提前返回,否则会很糟糕如N ^ 2):
if (!collectionHelper
.FieldMappingHelpers.Any(fmh => fmh.SelectedOption.Equals(fieldMappingOption)))
FieldMappingOption
是否有唯一键?如果是,请建议将Dictionary<Key, FieldMappingOption>
添加到collectionHelper
,然后使用.ContainsKey(key)
approaches O(1),例如
!collectionHelper
.SelectedFieldMappingOptions.ContainsKey(fieldMappingOption.SomeKey)
即使没有唯一的密钥,您也可以在HashCode
上使用合适的FieldMappingOption
并按键来获得类似的效果,尽管您需要考虑一下在发生哈希冲突时发生。
<强>可读性强>
外部for循环中的Where
谓词可以说是凌乱的,并且可以使用一些重构(为了便于阅读,如果不是为了表现)。
IMO大多数where子句可以作为元属性移动到FieldMappingOption
,例如总结
fmo.IsRequired
&& !fmo.IsCalculated
&& !fmo.FieldDefinition.Equals(MMPConstants.FieldDefinitions.FieldValue)
进入财产,例如fmo.MustBeValidated
等。
你可以通过重新排列&amp;&amp;和&amp; amp;&amp;最有可能首先失败的条款,但如果它影响代码的可读性流,则不会这样做。