当单步执行下面的代码时,我可以看到在设置IsActive属性之前创建了一个OtherThing实例。但是,在第二次枚举集合时,未设置IsActive。为什么这是真的?
public interface IISActive
{
bool IsActive { get; set; }
}
public class Thing : IISActive
{
public bool IsActive { get; set; }
}
public class OtherThing : IISActive
{
public bool IsActive { get; set; }
public OtherThing(IISActive arg)
{
IsActive = arg.IsActive;
}
}
class Program
{
static void Main(string[] args)
{
Console.Clear();
IEnumerable<IISActive> list = GetThings().Select(x => new OtherThing(x)); // .ToList() fixes it
foreach (IISActive t in list.Skip(1)) // object constructed here
t.IsActive = true;
foreach (IISActive t in list)
Console.WriteLine(t.IsActive.ToString());
// Actual Output:
// False
// False
// False
// Expected Output:
// False
// True
// True
Console.ReadKey();
}
static IEnumerable<IISActive> GetThings()
{
List <Thing> list = new List<Thing>();
list.Add(new Thing());
list.Add(new Thing());
list.Add(new Thing());
return list;
}
}
答案 0 :(得分:1)
您可以枚举现有的集合,但这不是您正在做的事情。
Select
会在枚举之前返回不会执行的枚举 - 例如使用foreach
或ToList
。此外,它不会缓存结果,因此当您再次枚举它时,它会再次运行完整的枚举逻辑。
- 包括选择器部分。
您要枚举两次,因此Select
选择器正在为每个Thing
运行两次。一旦进入第一次枚举,一次进入第二次。
当您使用ToList
时,您将枚举源并将每个项目附加到列表,然后返回该列表。由于您随后使用列表而不是Select
返回的枚举器,Select
选择器仅在您调用 ToList
时每个对象运行一次。< / p>
答案 1 :(得分:1)
它是由LINQ中的默认执行引起的。查询未在此行执行:
IEnumerable<IISActive> list = GetThings().Select(x => new OtherThing(x));
但是当你枚举IEnumerable
时。问题是,每次枚举都会执行Select
,所以实际上这两个foreach创建了五个OtherThing
对象(第一个枚举中有两个,第二个中有三个)。