像这样的编程模式经常出现:
int staleCount = 0;
fileUpdatesGridView.DataSource = MultiMerger.TargetIds
.Select(id =>
{
FileDatabaseMerger merger = MultiMerger.GetMerger(id);
if (merger.TargetIsStale)
staleCount++;
return new
{
Id = id,
IsStale = merger.TargetIsStale,
// ...
};
})
.ToList();
fileUpdatesGridView.DataBind();
fileUpdatesMergeButton.Enabled = staleCount > 0;
我不确定是否有更简洁的方法对此进行编码?
即使这样,这样做是不好的做法?
答案 0 :(得分:2)
不,这不严格"不良做法" (比如使用用户输入的字符串连接或使用goto
构建SQL查询)。
有时,此类代码比几个查询/ foreach
或无副作用Aggregate
调用更具可读性。另外,最好至少尝试编写foreach
和无副作用版本,以查看哪一个更易读/更容易证明正确。
请注意:
.ToList()
调用来懒散地执行LINQ查询这样的事实,但不会计算该值。答案 1 :(得分:0)
为什么不像这样编码:
var result=MultiMerger.TargetIds
.Select(id =>
{
FileDatabaseMerger merger = MultiMerger.GetMerger(id);
return new
{
Id = id,
IsStale = merger.TargetIsStale,
// ...
};
})
.ToList();
fileUpdatesGridView.DataSource = result;
fileUpdatesGridView.DataBind();
fileUpdatesMergeButton.Enabled = result.Any(r=>r.IsStale);
我认为这是一种不好的做法。您正在假设lambda表达式被强制执行,因为您调用了ToList。这是ToList当前版本的实现细节。如果将.NET 7.x中的ToList更改为返回一个半延迟转换IQueryable的对象,该怎么办?如果更改为并行运行lambda会怎么样?突然间,你的staleCount出现了并发问题。据我所知,由于您的代码所做的错误假设,这些都可能会破坏您的代码。
现在只要用一个id重复调用MultiMerger.GetMerger,那真的应该重新加工成一个连接,因为进行连接的逻辑(w | c)应该比你在那里编写的更有效率会扩展得更好,特别是如果MultiMerger的实现实际上是从数据库中提取数据(或者可能会更改为这样做)。
在将ToList()传递给Datasource之前调用ToList(),如果Datasource不使用新对象中的所有字段,那么您将(更快)并且占用更少的内存来跳过ToList并让它datasource只拉取它需要的字段。您所做的是将数据高度耦合到视图的确切要求,应尽可能避免这些要求。例如,如果您突然需要显示FileDatabaseMerger中存在的字段,但不在您当前的匿名对象中?现在你必须对控制器和视图进行更改以添加它,如果你刚刚传入IQueryable,你只需要更改视图。同样,更快,更少内存,更灵活,更易于维护。
希望这会有所帮助..这个问题确实应该发布代码审查,而不是stackoverflow。
进一步审核更新,以下代码会更好:
var result=MultiMerger.GetMergersByIds(MultiMerger.TargetIds);
fileUpdatesGridView.DataSource = result;
fileUpdatesGridView.DataBind();
fileUpdatesMergeButton.Enabled = result.Any(r=>r.TargetIsStale);
或
var result=MultiMerger.GetMergers().Where(m=>MultiMerger.TargetIds.Contains(m.Id));
fileUpdatesGridView.DataSource = result;
fileUpdatesGridView.DataBind();
fileUpdatesMergeButton.Enabled = result.Any(r=>r.TargetIsStale);