C# 在休息前将其取出

C# 在休息前将其取出,c#,foreach,C#,Foreach,我知道有很多方法可以做得更好,但我已经在现有的代码中看到了,现在我想知道这是否会有任何负面的副作用。请注意拆卸后的断裂。因此,我一般不关心迭代器,但是,我关心意外的行为(->潜在的异常) 编译器是否也可能以我不期望的方式优化某些东西?编译器和与应用程序接触的所有其他东西都保证SC-DRF(无数据竞争程序的顺序一致性),因此您不会看到您编写的程序和执行的程序之间的差异(这是完全不同的)。假设多个线程之间不共享项,那么编写它是完全安全的,并且除了在循环外部调用Remove之外,没有其他意外行为。编译

我知道有很多方法可以做得更好,但我已经在现有的代码中看到了,现在我想知道这是否会有任何负面的副作用。请注意拆卸后的断裂。因此,我一般不关心迭代器,但是,我关心意外的行为(->潜在的异常)


编译器是否也可能以我不期望的方式优化某些东西?

编译器和与应用程序接触的所有其他东西都保证SC-DRF(无数据竞争程序的顺序一致性),因此您不会看到您编写的程序和执行的程序之间的差异(这是完全不同的)。假设多个线程之间不共享
,那么编写它是完全安全的,并且除了在循环外部调用
Remove
之外,没有其他意外行为。

编译器生成对
Dispose()的调用
finally
块中执行的枚举器上执行,但这不应该是问题。如果在删除项后立即
中断
,则不会发生任何错误,因为您不再使用枚举器

如果您想以不同的方式进行(出于风格原因或其他原因),您可以这样做:

var item = items.FirstOrDefault(i => i.IsSomething);
if (item != null) {
    items.Remove(item);
}
它也有点短:)(我在这里假设您在集合中使用引用或可为空的类型)。

那么您可以这样做——在处理大型列表时效率更高(假设实体框架)


这减少了foreach的循环迭代次数,在foreach中迭代时不能更改列表


枚举基础集合时无法修改它。标准方法是将要删除的项保留在第二个列表中,然后在枚举项之后,再从项中删除每个项。

如果不继续枚举,则可以这样做。这是一个很好的问题,只需运行一次代码即可回答。告诉我们它是如何工作的它已经使用了很长一段时间了。我的情况就是这样。我只是想确保它是一个安全有效的模式(不过我以后不会使用它)它不起作用(因为
项的枚举数已更改)。你在这里期待什么意外的行为?什么会激发可能的UB?在我看来,这是一个很好的结构。@Dunken:您可以肯定,框架不会像正常行为那样默默地捕获异常。更重要的是,在一个性能关键的基本构造中,比如
foreach
-循环+1,但是如果
结构的
列表
,那么该代码有什么问题呢?@IlyaIvanov结构需要一种不同的方法,因为结构的默认值仍然是该结构的有效实例,只要将所有字段初始化为其默认值(结构不能为
null
)。例如,
int
被定义为结构/值类型,其默认值为0(不是
null
),这仍然是一个有效数字。@IlyaIvanov:正确,对于结构,您可以使用
Where
+
Any
+
First
var itemsWithSomething=items.Where(i=>i.IsSomething);bool hasSomething=itemsWithSomething.Any()
@TimSchmelter我想先添加一些类似的东西,但根据所用集合类型的这些扩展方法的实现,调用
Where
Any
first
(用于指定要删除的项)可能会多次迭代集合,因此,原始问题中的方法可能更好。性能差异可能并不重要,但谁知道该集合在内部做了什么。@Botz3000@TimSchmelter明白了。我想,
item!=如果
结构
,则null
不会编译,但我错了。感谢您的澄清。在第一次迭代后使用循环和中断似乎很奇怪。问题是您在从列表中删除项目时仍在对列表进行迭代。这解决不了任何问题。(你现在甚至有2个循环)@all是的,请忽略我在迭代时确实更改了列表。我举的例子可能是错误的做法,但它是有效的。
var item = items.FirstOrDefault(i => i.IsSomething);
if (item != null) {
    items.Remove(item);
}
var reducedList = items.where(a=>a.IsSomething).toList();
foreach(var item in reducedList)
{
    reducedList.Remove(item);
}