具有计算值的 Linq Select 投影
Linq Select projections with calculated values
我在将 Select 与匿名函数或运行时计算的其他值一起使用时注意到的是,每次访问输出 IEnumerable 对象时,投影都会重新计算该值。示例:
public class A
{
public string Name { get; set; }
public string Addr { get; set; }
}
public class B
{
public A Whatever {get;set;}
public int Id {get;set;}
}
Random rand = new Random();
IEnumerable<B> listOfBs = someListOfA.Select( x => new B()
{
Id = rand.Next(),
Whatever = x
});
我注意到,每次我解析列表 listOfB 并使用 Id 属性 时,都会用另一个 rand.Next()
.
重新评估该 Id
foreach( B b in listOfBs )
{
doSomething( b.Id );
}
我在有关 C# 投影的文档中没有看到会导致此问题的原因。它几乎就像 Select 生成一个匿名函数,每次访问时都会重新计算。那么,两个问题:
- 我看到的是什么行为。
- 如何避免这种情况,但仍然能够将一种类型的列表转换为另一种类型的列表。
如果我的错误示例代码表达了我的观点,请告诉我。
这是预料之中的,因为大多数 LINQ 方法都是惰性的——这意味着它们在需要结果之前不会枚举源。在您的特定场景中 listOfBs
实际上并不是 B
对象的物化集合。相反,它是关于 如何 将 someListOfA
转换为 B
对象集合的定义。 Select
returns 实现 IEnumerable<T>
并存储对源集合和投影委托的引用的对象。投影是在需要结果时完成的,例如当您遍历 foreach
中的集合时。如果您多次迭代,投影将被执行多次。这正是您所看到的。
调用ToList
或ToArray
立即实现结果:
IEnumerable<B> listOfBs = someListOfA.Select( x => new B()
{
Id = rand.Next(),
Whatever = x
}).ToList();
我在将 Select 与匿名函数或运行时计算的其他值一起使用时注意到的是,每次访问输出 IEnumerable 对象时,投影都会重新计算该值。示例:
public class A
{
public string Name { get; set; }
public string Addr { get; set; }
}
public class B
{
public A Whatever {get;set;}
public int Id {get;set;}
}
Random rand = new Random();
IEnumerable<B> listOfBs = someListOfA.Select( x => new B()
{
Id = rand.Next(),
Whatever = x
});
我注意到,每次我解析列表 listOfB 并使用 Id 属性 时,都会用另一个 rand.Next()
.
foreach( B b in listOfBs )
{
doSomething( b.Id );
}
我在有关 C# 投影的文档中没有看到会导致此问题的原因。它几乎就像 Select 生成一个匿名函数,每次访问时都会重新计算。那么,两个问题:
- 我看到的是什么行为。
- 如何避免这种情况,但仍然能够将一种类型的列表转换为另一种类型的列表。
如果我的错误示例代码表达了我的观点,请告诉我。
这是预料之中的,因为大多数 LINQ 方法都是惰性的——这意味着它们在需要结果之前不会枚举源。在您的特定场景中 listOfBs
实际上并不是 B
对象的物化集合。相反,它是关于 如何 将 someListOfA
转换为 B
对象集合的定义。 Select
returns 实现 IEnumerable<T>
并存储对源集合和投影委托的引用的对象。投影是在需要结果时完成的,例如当您遍历 foreach
中的集合时。如果您多次迭代,投影将被执行多次。这正是您所看到的。
调用ToList
或ToArray
立即实现结果:
IEnumerable<B> listOfBs = someListOfA.Select( x => new B()
{
Id = rand.Next(),
Whatever = x
}).ToList();